From: Paul D. Lathrop
Subject: Deleting directories in lisp
Date: 
Message-ID: <uh9sqrhe0ev8b0@corp.supernews.com>
I know this may be a completely newbie question, but please bear with me. I
am writing some file-manipulation functions that I would find useful and I
have run into a problem I cannot seem to find a method of using lisp to
delete directories. I have tried using 'delete-file' with the directory
pathname as an argument and I get

Error: Failed to DELETE file D:/code/lisp/bleh/: 5: Access is denied.(5)

Any chance someone out there can help me?

From: Erik Naggum
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <3233773080842596@naggum.net>
* Paul D. Lathrop
| I am writing some file-manipulation functions that I would find useful and I
| have run into a problem I cannot seem to find a method of using lisp to
| delete directories.

  I think you should not do that.  I think it is a serious error for any user
  program to assume the role of administrator, even over files it has created.
  I am constantly annoyed by user programs that assume that I want to overwrite
  files.  That is none of their business.  If a file exists with the name they
  also want to use, it may still be important to me, and I would really like
  the user program not to delete its contents so I have to drag it back from a
  backup disk.  With real file versions, this would never be a problem, but
  since Unix and Windows do not suppport file versions, the accidental loss of
  information they so strongly favor and cause is a major pain.  So I think
  that if you want system administration tools, you should not look for help in
  the language, but in the system administration subsystem, and you should make
  a strong distinction between user program and administrators.  Not so strong,
  of course, that you would need to do a serious change of identity, but strong
  enough that you do not accidentally lose or destroy information.
-- 
  Guide to non-spammers: If you want to send me a business proposal, please be
  specific and do not put "business proposal" in the Subject header.  If it is
  urgent, do not use the word "urgent".  If you need an immediate answer, give
  me a reason, do not shout "for your immediate attention".  Thank you.
From: Paul D. Lathrop
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <uh9unopk3bfge0@corp.supernews.com>
"Erik Naggum" <····@naggum.net> wrote in message
·····················@naggum.net...
>   I think you should not do that.  I think it is a serious error for any
user
>   program to assume the role of administrator, even over files it has
created.
>   I am constantly annoyed by user programs that assume that I want to
overwrite
>   files.  That is none of their business.  If a file exists with the name
they
>   also want to use, it may still be important to me, and I would really
like
>   the user program not to delete its contents so I have to drag it back
from a
>   backup disk.  With real file versions, this would never be a problem,
but
>   since Unix and Windows do not suppport file versions, the accidental
loss of
>   information they so strongly favor and cause is a major pain.  So I
think
>   that if you want system administration tools, you should not look for
help in
>   the language, but in the system administration subsystem, and you should
make
>   a strong distinction between user program and administrators.  Not so
strong,
>   of course, that you would need to do a serious change of identity, but
strong
>   enough that you do not accidentally lose or destroy information.

I understand your points, and they are good, but the tool I am writing is
not making any assumptions i.e. I am going to ASK it to delete a directory,
not have it do so as a side effect of some other function. I dislike
programs that take power away from the user. This tool is to GIVE me power
over my files, not take it away.
From: Tim Daly, Jr.
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <m3vg8aao6m.fsf@ponder.intern>
"Paul D. Lathrop" <········@chartermi.net> writes:

> I know this may be a completely newbie question, but please bear with me. I
> am writing some file-manipulation functions that I would find useful and I
> have run into a problem I cannot seem to find a method of using lisp to
> delete directories. I have tried using 'delete-file' with the directory
> pathname as an argument and I get
> 
> Error: Failed to DELETE file D:/code/lisp/bleh/: 5: Access is denied.(5)
> 
> Any chance someone out there can help me?
> 

It looks like you might be doing this in windows.  If you try to
remove a directory that is currently in use, the error reported by
windows is "Access Denied".  Make sure that no running programs
started out of that directory, and that no files are currently open in
that directory, and give it another shot. :)

(Just a guess).

-Tim

-- 
Turing Stable: (adj) The property of continuing to be Turing complete,
after running for an hour.
From: Paul D. Lathrop
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <uhbje2hqmf4ld9@corp.supernews.com>
"Tim Daly, Jr." <···@ponder.intern> wrote in message
···················@ponder.intern...
> "Paul D. Lathrop" <········@chartermi.net> writes:
>
> > I know this may be a completely newbie question, but please bear with
me. I
> > am writing some file-manipulation functions that I would find useful and
I
> > have run into a problem I cannot seem to find a method of using lisp to
> > delete directories. I have tried using 'delete-file' with the directory
> > pathname as an argument and I get
> >
> > Error: Failed to DELETE file D:/code/lisp/bleh/: 5: Access is denied.(5)
> >
> > Any chance someone out there can help me?
> >
>
> It looks like you might be doing this in windows.  If you try to
> remove a directory that is currently in use, the error reported by
> windows is "Access Denied".  Make sure that no running programs
> started out of that directory, and that no files are currently open in
> that directory, and give it another shot. :)
>
> (Just a guess).
>
> -Tim

I appreciate this idea, but I am running this on a test directory tree that
has nothing open in it nor does it have any programs running in it. *sigh*
With all the reading I have been doing it looks like Common Lisp defines a
facility to create directories (ensure-directories-exist) but no facility to
destroy them.
From: Thomas M. Magee
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <7f6ff162.0206250918.4fd676c8@posting.google.com>
"Paul D. Lathrop" <········@chartermi.net> wrote in message news:<··············@corp.supernews.com>...
> "Tim Daly, Jr." <···@ponder.intern> wrote in message
> ···················@ponder.intern...
> > "Paul D. Lathrop" <········@chartermi.net> writes:
> >
> > > I know this may be a completely newbie question, but please bear with
>  me. I
> > > am writing some file-manipulation functions that I would find useful and
>  I
> > > have run into a problem I cannot seem to find a method of using lisp to
> > > delete directories. I have tried using 'delete-file' with the directory
> > > pathname as an argument and I get
> > >
> > > Error: Failed to DELETE file D:/code/lisp/bleh/: 5: Access is denied.(5)
> > >
> > > Any chance someone out there can help me?
> > >
> >
> > It looks like you might be doing this in windows.  If you try to
> > remove a directory that is currently in use, the error reported by
> > windows is "Access Denied".  Make sure that no running programs
> > started out of that directory, and that no files are currently open in
> > that directory, and give it another shot. :)
> >
> > (Just a guess).
> >
> > -Tim
> 
> I appreciate this idea, but I am running this on a test directory tree that
> has nothing open in it nor does it have any programs running in it. *sigh*
> With all the reading I have been doing it looks like Common Lisp defines a
> facility to create directories (ensure-directories-exist) but no facility to
> destroy them.

I could not find this function in Paul Graham's handy dandy Lisp
reference section in the back of ANSI Common Lisp, so I don't know if
this is a standard lisp function or not, but the clisp implementation
of common lisp contains a function "delete-dir" that does the job
nicely.

Example:

        (delete-dir "~/blech/")


The function returned true for me if successful, but returned a Unix
EILSEQ error if the directory did not exist.  I think that error must
be a bug in the clisp port to Darwin, which is what I am using it on.
From: Paul D. Lathrop
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <uhhbh7hdl57a90@corp.supernews.com>
Yes I've found that deleting directories appears to be an
implementation-dependent subject. *sigh* Seems silly to me. Ah, well.


"Thomas M. Magee" <···@tommagee.com> wrote in message
·································@posting.google.com...
> "Paul D. Lathrop" <········@chartermi.net> wrote in message
news:<··············@corp.supernews.com>...
> > "Tim Daly, Jr." <···@ponder.intern> wrote in message
> > ···················@ponder.intern...
> > > "Paul D. Lathrop" <········@chartermi.net> writes:
> > >
> > > > I know this may be a completely newbie question, but please bear
with
> >  me. I
> > > > am writing some file-manipulation functions that I would find useful
and
> >  I
> > > > have run into a problem I cannot seem to find a method of using lisp
to
> > > > delete directories. I have tried using 'delete-file' with the
directory
> > > > pathname as an argument and I get
> > > >
> > > > Error: Failed to DELETE file D:/code/lisp/bleh/: 5: Access is
denied.(5)
> > > >
> > > > Any chance someone out there can help me?
> > > >
> > >
> > > It looks like you might be doing this in windows.  If you try to
> > > remove a directory that is currently in use, the error reported by
> > > windows is "Access Denied".  Make sure that no running programs
> > > started out of that directory, and that no files are currently open in
> > > that directory, and give it another shot. :)
> > >
> > > (Just a guess).
> > >
> > > -Tim
> >
> > I appreciate this idea, but I am running this on a test directory tree
that
> > has nothing open in it nor does it have any programs running in it.
*sigh*
> > With all the reading I have been doing it looks like Common Lisp defines
a
> > facility to create directories (ensure-directories-exist) but no
facility to
> > destroy them.
>
> I could not find this function in Paul Graham's handy dandy Lisp
> reference section in the back of ANSI Common Lisp, so I don't know if
> this is a standard lisp function or not, but the clisp implementation
> of common lisp contains a function "delete-dir" that does the job
> nicely.
>
> Example:
>
>         (delete-dir "~/blech/")
>
>
> The function returned true for me if successful, but returned a Unix
> EILSEQ error if the directory did not exist.  I think that error must
> be a bug in the clisp port to Darwin, which is what I am using it on.
From: Erik Naggum
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <3234021360326545@naggum.net>
* Paul D. Lathrop
| Yes I've found that deleting directories appears to be an
| implementation-dependent subject. *sigh* Seems silly to me. Ah, well.

  Directories are implementation-dependent by their very nature.  What is
  slightly painful is that Common Lisp vendors on operating system families
  have somehow failed to agree on how to make these simple things portable
  within the famiilies.  This has some historical reasons, which mostly have to
  do with how Common LIsp people tend to regard the Unix or Windows way as
  "wrong" and go on to reinvent their own "right" solution differently.  There
  is a strong tradition from the Lisp machines to do certain things a certain
  way, but it tends to be hard to splice Lisp machine semantics into Unix or
  Windows.  Please try to understand that Common Lisp is not a one-operating-
  system-language or a one-implementation language.

  You are supposed to know which is language and which is operating system and
  behave reasonably accordingly.  If it say it seems silly to you, that only
  means that you seem silly to those who have figured this out and appreciate
  the difference because it does not make undue requirements on the environment
  of a Common Lisp implementation.

[ Please quote only the relevant text of your replies and answer below the
  relevant text you quote.  Microsoft screwed up.  Make another choice. ]
-- 
  Guide to non-spammers: If you want to send me a business proposal, please be
  specific and do not put "business proposal" in the Subject header.  If it is
  urgent, do not use the word "urgent".  If you need an immediate answer, give
  me a reason, do not shout "for your immediate attention".  Thank you.
From: Paul D. Lathrop
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <uhhmmk5et5v29c@corp.supernews.com>
"Erik Naggum" <····@naggum.net> wrote in message
·····················@naggum.net...
>   Directories are implementation-dependent by their very nature.  What is
>   slightly painful is that Common Lisp vendors on operating system
families
>   have somehow failed to agree on how to make these simple things portable
>   within the famiilies.  This has some historical reasons, which mostly
have to
>   do with how Common LIsp people tend to regard the Unix or Windows way as
>   "wrong" and go on to reinvent their own "right" solution differently.
There
>   is a strong tradition from the Lisp machines to do certain things a
certain
>   way, but it tends to be hard to splice Lisp machine semantics into Unix
or
>   Windows.  Please try to understand that Common Lisp is not a
one-operating-
>   system-language or a one-implementation language.

In that case, explain to me why *creating* a directory is *not*
implementation-dependent and is, in fact, part of the language
specification.

>   You are supposed to know which is language and which is operating system
and
>   behave reasonably accordingly.  If it say it seems silly to you, that
only
>   means that you seem silly to those who have figured this out and
appreciate
>   the difference because it does not make undue requirements on the
environment
>   of a Common Lisp implementation.

I would like to politely point out that the above paragraph makes you come
off as incredibly arrogant, while the grammatical mistake makes you come off
as incredibly ignorant. Try not to talk like you are the be all and end all
of Lisp coders.

> [ Please quote only the relevant text of your replies and answer below the
>   relevant text you quote.  Microsoft screwed up.  Make another choice. ]

And this, of coursse, cements the above comment.

Have a nice day.

Paul D. Lathrop
From: Erik Naggum
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <3234029285705408@naggum.net>
* Paul D. Lathrop
| In that case, explain to me why *creating* a directory is *not*
| implementation-dependent and is, in fact, part of the language specification.

  I did not know that you had a personality disorder that required that you be
  hugged and kissed before you could take criticism.  I regret answering you.
  The general rule on USENET is: Grow the hell up, _then_ post.  Deal with it.
-- 
  Guide to non-spammers: If you want to send me a business proposal, please be
  specific and do not put "business proposal" in the Subject header.  If it is
  urgent, do not use the word "urgent".  If you need an immediate answer, give
  me a reason, do not shout "for your immediate attention".  Thank you.
From: Paul D. Lathrop
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <uhhoipghpv33bb@corp.supernews.com>
"Erik Naggum" <····@naggum.net> wrote in message
·····················@naggum.net...
>   The general rule on USENET is: Grow the hell up, _then_ post.  Deal with
it.

Interesting how you can show that you *know* the rule while showing you
can't follow it. Thanks for the pointer. Sorry I didn't stroke your ego
properly.
From: Erik Naggum
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <3234031425220075@naggum.net>
* Paul D. Lathrop
| Interesting how you can show that you *know* the rule while showing you can't
| follow it. Thanks for the pointer. Sorry I didn't stroke your ego properly.

  Do you feel better now?  If so, could you get back on track and try to focus
  on the _problem_ you had?  It was something with Common Lisp and directories,
  I seem to recall.  Your personality disorders and personal problems are _not_
  the business of this newsgroup, no matter how you feel.  So, is there any way
  we can help you solve your _problem_ and get you to quit attacking people
  like you seem to need when you are given an answer you were not prepared for?
  You asked for help, you got an answer and an opportunity to learn from it,
  but chose to react like a whining little kid.  Nobody cares what some jerk
  finds "silly".  So you were told to shut up, and had to react even more
  childishly, but this is _not_ a forum for whining little kids.  It is a forum
  for programmers.  Egos are equally irrelvant.  Learn to take charge of your
  own emotions, keep them out of other people's faces, and stick to the task at
  hand.  You had a _programming_ problem, did you not?  Lots of people were
  willing to help with your _programming_ problem, but if you insist on being a
  whining little kid, you will not get help from anyone for a very long time.
  So, which is more important to you: To whine or to get help to solve your
  problems?  It is a _really_ simple choice.  Just make it and behave in a way
  that communicates goal-directed intelligence.  Do you understand this?
-- 
  Guide to non-spammers: If you want to send me a business proposal, please be
  specific and do not put "business proposal" in the Subject header.  If it is
  urgent, do not use the word "urgent".  If you need an immediate answer, give
  me a reason, do not shout "for your immediate attention".  Thank you.
From: Tim Bradshaw
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <ey33cvaanfg.fsf@cley.com>
* Paul D Lathrop wrote:
> In that case, explain to me why *creating* a directory is *not*
> implementation-dependent and is, in fact, part of the language
> specification.

It isn't, really.  ENSURE-DIRECTORIES-EXIST is some kind of minimal
get-you-through-the-night thing which any filesystem is likely to
support - `given this path, try and make it be the case that
everything is OK for me to create a file here'.  It just avoids
exposing all the complicated issues about directories that deleting
them, or probing them, or pretty much anything else exposes.

Even within the domain of Unix or near Unix-clone filesystems there
are obscurities here - should 

    (probe-file (make-pathname :directory '(:absolute)
                               :name "usr"))

Return true on a Unix filesystem?  If it does, does it make sense to
delete that `file'? What about

    (probe-file (make-pathname :directory '(:absolute "usr")
                               :name nil :type nil :version nil))

?

Now remember that there are other filesystems, and they don't all work
the same way.  On the LMFS, I think that the file corresponding to a
directory FOO> was called FOO.DIRECTORY (what was it on the FEP
filesystem?), VMS I think has something the same.  Other filesystems
maybe don't have files corresponding to directories (does DOS, really,
does the mac (and what is its filesystem now, anyway, if it FFS?)).

It's one thing to provide a minimal hack like
ENSURE-DIRECTORIES-EXIST, it's a huge amount more to provide some
general-purpose interface, even if one could be designed.  Especially
if there is more than one interesting filesystem in the world.  The
hegemony of Unix(oid) filesystems has done almost as much damage to
people's ability to think about Unix as the hegemony of C-on-Unix has
to people's ability to think about characters.

The good news is that, if you only want to live on Unix or DOS, then
the amount of work you need to do to support the filesystem is
probably tiny.  In my system I have 55 lines of copiously-commented
(most of those lines are comments, I think, and most of the rest are
to do with signalling appropriate errors, or not)
implementation-specific code to deal with directories, which supports
one implementation.  I also have probably several times that amount of
general pathname-bashing code which is sort-of-portable in the sense
that it's not Lisp implementation dependent but would not work except
on Unix or DOS - for instance functions to canonicalise namestrings to
have forward slashes and so on.

Out of interest the exported implementation-specific functions are:

    directory-subdirectories - return the subdirectories only of a
     directory (not including . or .. on Unix/DOS);

    directory-files - return everything *but* subdirectories;

    directory-exists-p - does a directory exist?

    directory-truename - return the true name of a directory;

    delete-directory - delete a directory.

This isn't intended as a complete set, but it's enough to do a lot of
fairly intensive filesystem bashing up to and including mirroring
directory trees.  It certainly would not work other than on Unix/Linux
or Windows, but unlike CL, it wasn't designed to.

I'm always amazed by how much time people seem to spend worrying about
issues like this.  I've spend the last 6-8 months working on a system
which does really a lot of talking to the OS &c, and these
implementation-specific things have been just in the noise in terms of
time spent, lines of code written, or difficulty.

--tim
From: Paul D. Lathrop
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <uhia5or4bvd611@corp.supernews.com>
"Tim Bradshaw" <···@cley.com> wrote in message
····················@cley.com...
> * Paul D Lathrop wrote:
> > In that case, explain to me why *creating* a directory is *not*
> > implementation-dependent and is, in fact, part of the language
> > specification.
>
> It isn't, really.  ENSURE-DIRECTORIES-EXIST is some kind of minimal
> get-you-through-the-night thing which any filesystem is likely to
> support - `given this path, try and make it be the case that
> everything is OK for me to create a file here'.  It just avoids
> exposing all the complicated issues about directories that deleting
> them, or probing them, or pretty much anything else exposes.
>
> Even within the domain of Unix or near Unix-clone filesystems there
> are obscurities here - should
>
>     (probe-file (make-pathname :directory '(:absolute)
>                                :name "usr"))
>
> Return true on a Unix filesystem?  If it does, does it make sense to
> delete that `file'? What about
>
>     (probe-file (make-pathname :directory '(:absolute "usr")
>                                :name nil :type nil :version nil))
>
> ?
>
> Now remember that there are other filesystems, and they don't all work
> the same way.  On the LMFS, I think that the file corresponding to a
> directory FOO> was called FOO.DIRECTORY (what was it on the FEP
> filesystem?), VMS I think has something the same.  Other filesystems
> maybe don't have files corresponding to directories (does DOS, really,
> does the mac (and what is its filesystem now, anyway, if it FFS?)).
>
> It's one thing to provide a minimal hack like
> ENSURE-DIRECTORIES-EXIST, it's a huge amount more to provide some
> general-purpose interface, even if one could be designed.  Especially
> if there is more than one interesting filesystem in the world.  The
> hegemony of Unix(oid) filesystems has done almost as much damage to
> people's ability to think about Unix as the hegemony of C-on-Unix has
> to people's ability to think about characters.
>
> The good news is that, if you only want to live on Unix or DOS, then
> the amount of work you need to do to support the filesystem is
> probably tiny.  In my system I have 55 lines of copiously-commented
> (most of those lines are comments, I think, and most of the rest are
> to do with signalling appropriate errors, or not)
> implementation-specific code to deal with directories, which supports
> one implementation.  I also have probably several times that amount of
> general pathname-bashing code which is sort-of-portable in the sense
> that it's not Lisp implementation dependent but would not work except
> on Unix or DOS - for instance functions to canonicalise namestrings to
> have forward slashes and so on.
>
> Out of interest the exported implementation-specific functions are:
>
>     directory-subdirectories - return the subdirectories only of a
>      directory (not including . or .. on Unix/DOS);
>
>     directory-files - return everything *but* subdirectories;
>
>     directory-exists-p - does a directory exist?
>
>     directory-truename - return the true name of a directory;
>
>     delete-directory - delete a directory.
>
> This isn't intended as a complete set, but it's enough to do a lot of
> fairly intensive filesystem bashing up to and including mirroring
> directory trees.  It certainly would not work other than on Unix/Linux
> or Windows, but unlike CL, it wasn't designed to.
>
> I'm always amazed by how much time people seem to spend worrying about
> issues like this.  I've spend the last 6-8 months working on a system
> which does really a lot of talking to the OS &c, and these
> implementation-specific things have been just in the noise in terms of
> time spent, lines of code written, or difficulty.
>
> --tim


Thank you, Tim, for clearing that up. I had started to come to a similar
conclusion on my own, but I certainly appreciate your parting of the haze on
this matter. Now that I have dug deeper into my implementation I have found
they have provided several methods of dealing with the issues that were
tripping me up.

Paul D. Lathrop
From: Andreas Hinze
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <3D198D0A.A5EE8E44@smi.de>
Tim Bradshaw wrote:
> 
> The good news is that, if you only want to live on Unix or DOS, then
> the amount of work you need to do to support the filesystem is
> probably tiny.  In my system I have 55 lines of copiously-commented
> (most of those lines are comments, I think, and most of the rest are
> to do with signalling appropriate errors, or not)
> implementation-specific code to deal with directories, which supports
> one implementation.  I also have probably several times that amount of
> general pathname-bashing code which is sort-of-portable in the sense
> that it's not Lisp implementation dependent but would not work except
> on Unix or DOS - for instance functions to canonicalise namestrings to
> have forward slashes and so on.
> 
> Out of interest the exported implementation-specific functions are:
> 
>     directory-subdirectories - return the subdirectories only of a
>      directory (not including . or .. on Unix/DOS);
> 
>     directory-files - return everything *but* subdirectories;
> 
>     directory-exists-p - does a directory exist?
> 
>     directory-truename - return the true name of a directory;
> 
>     delete-directory - delete a directory.
> 
What do you think about making it public ? I would assume that a lot
of people have to deal with directories. And if others include code
for their plattform maybe this will become a new package for cliki's
 compatibility layers page ;-)

Best
AHz
From: Tim Bradshaw
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <ey36606nwub.fsf@cley.com>
* Andreas Hinze wrote:
> What do you think about making it public ? I would assume that a lot
> of people have to deal with directories. And if others include code
> for their plattform maybe this will become a new package for cliki's
>  compatibility layers page ;-)

I guess I could do so, but my point really was that this is a really
negligible amount of code - such a small amount that I wouldn't really
think it was worth providing a library for.  It's also plastered with
application-specific error classes &c at the moment.

The more interesting things are code that is (in theory, we don't
currently run on more than one implementation) portable, and does
various useful things with pathnames, mostly in a Unix/DOS context,
such as ensuring a user-inputted string names a directory, and
`demerging' directories.  `Demerging' a directory means taking (say)
`/a/b/c/d/f' and `/a/b/c/' and returning `d/f` or `/a/b/c/f/` and
`/a/b/c/d/` and returning `../f/' in Unix terms.  It's very useful if
you want to write things like Makefiles with relative directory names
in.  Again, I have code that does all this but it's covered in
application stuff that I don't want to give away and don't have time
to expunge, and it's also not really library-quality - it works in the
context of the application but has some known deficiencies (for
instance the demerging code on DOS will happily demerge things whose
drive letters are different, since it only considers directories, so
it will decide that the relative path from `D:/foo/bar/' to `E:/foo/'
is `../').

Really, I'm trying to make a Gabrielesque anti-abstraction argument
here.  It would probably be possible to provide a fairly comprehensive
Unix/DOS-portable pathname library which would have all sorts of cool
stuff.  But to do that, and to make it library quality code which will
be genuinely reusable and will work outside its original context would
involve a lot of work and several hard decisions - which work and
decisions are a small part of why this stuff isn't in the standard.
It's often much easier to just write stuff which works for an
application, because there you *know* the context.

--tim
From: Paolo Amoroso
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <O7gdPeRoW925pfyZndbvGTGo=h6c@4ax.com>
On Wed, 26 Jun 2002 11:44:42 +0200, Andreas Hinze <···@smi.de> wrote:

> Tim Bradshaw wrote:
[...]
> > probably tiny.  In my system I have 55 lines of copiously-commented
[...]
> > implementation-specific code to deal with directories, which supports
[...]
> What do you think about making it public ? I would assume that a lot

A simple directory access interface is available as part of CLOCC (Common
Lisp Open Code Collection):

  http://clocc.sourceforge.net

See the file src/port/path.lisp.


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://www.paoloamoroso.it/ency/README
From: Paul D. Lathrop
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <uhpcccrrm3287d@corp.supernews.com>
Thank you all for your help. In case anyone is interested, here's
how I worked it out. Note, this only works in Xanalys Lispworks
for Windows.

;;;;; Start Source File
;;;;; Directory flattening utility
;;;;;   for Windows and Xanalys Lispworks
;;;;;
;;;;; The author of this code gives explicit permission
;;;;;   to distribute, changed or unchanged, any or all
;;;;;   of this code. This code is distributed as-is
;;;;;   without guarantee or warranty of any kind.

(defpackage "FLATTEN"
  (:use "COMMON-LISP")
  (:export flatten))

(in-package "FLATTEN")

(import 'lw:delete-directory)

(defparameter *working-directory*
  (make-pathname :host "d" :directory '(:absolute "code" "lisp"))
  "Parameter storing the current working directory.")

(defparameter *file-list* nil
  "Parameter used to store the list of files to move.")

(defparameter *directory-list* nil
  "Parameter used to store the list of subdirectories to remove.")

(defun flatten(path)
  "Recursively moves all files from subdirectories to the directory passed
to flatten."
  (progn
    ;; Set the working directory.
    (setf *working-directory* (make-pathname :host (pathname-host path)
          :directory (pathname-directory
        path)))
    ;; Collect the files and directories.
    (tr-flatten *working-directory*)
    ;; Move the files.
    (move-multiple-files *file-list* *working-directory*)
    (setf *file-list* nil)
    ;; Remove the directories.
    (delete-multiple-directories (nreverse *directory-list*))
    (setf *directory-list* nil)))

(defun tr-flatten(path)
  ;; Here we accumulate the files into  *file-list*
  ;;  and the directories into *directory-list*
  (let ((directory-listing (directory
       (make-pathname :host (pathname-host path)
        :directory (pathname-directory
             path)))))
    (dolist (directory-entry directory-listing)
     (if (directoryp directory-entry)
  (progn
    (tr-flatten directory-entry)
    (push directory-entry *directory-list*))
       (push directory-entry *file-list*)))))

(defun directoryp(path)
  "Returns t if its argument refers to a directory."
  ;; Tests the last character to see if it is a /.
  ;; This probably only works for Lispworks.
  (let ((pathstring (get-full-path-string path)))
    (equal (char pathstring (- (length pathstring) 1)) (character "/"))))

(defun move-multiple-files(file-list newpath)
  "Moves a list of files."
  (dolist (current-file file-list)
   (move-file current-file newpath)))

(defun move-file(oldpath newpath)
  "Moves a file."
  (cond ((not (probe-file oldpath))
  (error "\"~A\" is of the wrong form, or does not exist." oldpath))
 ((not (probe-file (make-pathname :host (pathname-host newpath)
      :directory (pathname-directory
           newpath))))
  (error "\"~A\" is of the wrong form, or does not exist." newpath))
 (t (rename-file oldpath newpath))))

(defun delete-multiple-directories(directory-list)
  "Deletes a list of directories."
  (dolist (current-dir directory-list)
   (delete-directory current-dir))) ;; Lispworks only!

(defun get-full-path-string(path)
  "Returns the full path of its argument in string format."
  ;; We just build a string segment by segment.
  (let ((hoststring (concatenate 'string (pathname-host path) ":/"))
 (dirlist (add-foreslash (cdr (pathname-directory path))))
 (filename nil)
 (dirstring ""))
    (dolist (element dirlist)
     (setf dirstring (concatenate 'string dirstring element)))
    (setf dirstring (concatenate 'string hoststring dirstring))
    (if (not (eq (pathname-name path) :unspecific))
 (progn
   (setf filename (pathname-name path))
   (setf dirstring (concatenate 'string dirstring filename))
   (setf dirstring (concatenate 'string dirstring "."))
   (setf dirstring (concatenate 'string dirstring (pathname-type
         path)))))
    dirstring))

(defun add-foreslash(lst)
  "Takes a list of strings and places the '/' character at the end of each"
  (let ((acc nil)
 (elements lst))
    (dotimes (i (length lst))
      (push (concatenate 'string (car elements) "/") acc)
      (setf elements (cdr elements)))
    (reverse acc)))
From: Paul Foley
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <m2y9cyx0sm.fsf@mycroft.actrix.gen.nz>
On Fri, 28 Jun 2002 14:57:11 -0400, Paul D Lathrop wrote:

> (defpackage "FLATTEN"
>   (:use "COMMON-LISP")
>   (:export flatten))

    (:export "FLATTEN"))

otherwise you'll intern FLATTEN in the current package, and collide
with it if you try to (use-package "FLATTEN") or something latter.

> (defparameter *working-directory*
>   (make-pathname :host "d" :directory '(:absolute "code" "lisp"))
>   "Parameter storing the current working directory.")

> (defparameter *file-list* nil
>   "Parameter used to store the list of files to move.")

> (defparameter *directory-list* nil
>   "Parameter used to store the list of subdirectories to remove.")

Don't do that.  There's no reason for these things to be specials.

> (defun flatten(path)
>   "Recursively moves all files from subdirectories to the directory passed
> to flatten."
>   (progn
>     ;; Set the working directory.
>     (setf *working-directory* (make-pathname :host (pathname-host path)
>           :directory (pathname-directory
>         path)))
>     ;; Collect the files and directories.
>     (tr-flatten *working-directory*)
>     ;; Move the files.
>     (move-multiple-files *file-list* *working-directory*)
>     (setf *file-list* nil)
>     ;; Remove the directories.
>     (delete-multiple-directories (nreverse *directory-list*))
>     (setf *directory-list* nil)))

Is

(defun flatten-directory (path)
  (labels ((rec (dir)
             (dolist (ent (directory dir))
               (cond ((or (pathname-name ent) (pathname-type ent))
                      (unless (eql dir path)
                        (rename-file ent (make-pathname
                                           :directory (pathname-directory path)
                                           :defaults ent))))
                     (t
                      (rec ent) (lw:delete-directory ent))))))
    (rec path)))

close to what you're looking for?

-- 
Quid enim est stultius quam incerta pro certis habere, falsa pro veris?
                                                                 -- Cicero
(setq reply-to
  (concatenate 'string "Paul Foley " "<mycroft" '(··@) "actrix.gen.nz>"))
From: Pekka P. Pirinen
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <u3cv0q3r8.fsf@globalgraphics.com>
"Paul D. Lathrop" <········@chartermi.net> writes:
> (defun directoryp(path)
>   "Returns t if its argument refers to a directory."
>   ;; Tests the last character to see if it is a /.
>   ;; This probably only works for Lispworks.
>   (let ((pathstring (get-full-path-string path)))
>     (equal (char pathstring (- (length pathstring) 1)) (character "/"))))

This is overly complicated.  It's a good rule of thumb that if you end
up using namestrings for something that's not communicating with the
user or passing filenames in and out of Lisp, it's probably the wrong
solution.  Pathname computations are better done using pathnames.

In this case, test NAME, TYPE and VERSION fields for being NIL or
:UNSPECIFIC (possibly :VERSION :NEWEST, if your system uses that).  In
LispWorks, this is already available as SYSTEM:DIRECTORY-PATHNAME-P.
-- 
Pekka P. Pirinen
Mail should be private, whether on paper or on disk.  Public gatherings
should be a right, whether virtual or in person.
From: Kaz Kylheku
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <afb313$k1u$1@luna.vcn.bc.ca>
In article <··············@corp.supernews.com>, Paul D. Lathrop wrote:
> I know this may be a completely newbie question, but please bear with me. I
> am writing some file-manipulation functions that I would find useful and I
> have run into a problem I cannot seem to find a method of using lisp to
> delete directories. I have tried using 'delete-file' with the directory
> pathname as an argument and I get
> 
> Error: Failed to DELETE file D:/code/lisp/bleh/: 5: Access is denied.(5)
> 
> Any chance someone out there can help me?

If you want to do platform-specific file manipulation, you have to drop
down a notch and access your operating system's service functions.
There is no portable way to do this; Lisp systems have different 
FFI's (foreign function interfaces) and of course operating systems
differ from each other as well. Some Lisp systems have a ready made
package of system calls; see if yours has something like that.

In Meta-CVS, I created a little layer which provides some POSIX functions as
Lisp functions; e.g. I can unlink a file using (unlink <pathname>), scan
directories with (opendir ...) (readdir ...) and (closedir ...) and so on. With
some nice macros, a recursive directory deletion (analogous to the POSIX
command ``rm -rf'') ends up looking very slick:

  (defun delete-recursive (dir-or-file)
    (for-each-file-info (fi dir-or-file :postorder t)
      (if (directory-p fi)
        (rmdir (file-name fi))
        (unlink (file-name fi)))))

It may help to remember that the ANSI C and C++ languages have no directory
deletion function either.  It's just that these languages make it far easier to
access the operating system specific functions, since the bindings to these
functions are already expressed in C. Not to mention that there is a class of
operating systems which share the same POSIX bindings. So you are only at
a slight disadvantage in Lisp, due to having to deal with foreign function
interfaces or system call packages that are incompatible among different
Lisps.

A good strategy is to identify what services you need and then write a layer
which provides these services. That layer can be retargetted to different
Lisp systems. You can write a separate file for each Lisp system, or
use #+ and #- feature tests to selectively read code.

In Meta-CVS, I have a file called clisp-linux.lisp, and cmucl-unix.lisp.
The latter is an ongoing, incomplete port to CMUCL. In clisp-linux.lisp
(opendir ...) is defined like this:

  (defun opendir (dir)
    (cond
      ((null-to-nil (linux:opendir dir)))
      (t (error (make-condition 'open-dir-error :dir dir)))))

This uses the LINUX package of glibc bindings that comes with CLISP
and can be optionally built.

In cmucl-unix.lisp, it looks like this:

  (defun opendir (dir)
    (cond
      ((unix:open-dir dir))
      (t (error (make-condition 'open-dir-error :dir dir)))))

It's very similar, except for the spelling of open-dir, the package
name, and that NIL is already returned if there is an error.

A more interesting case study is my current-dir-restore macro which
remembers the current working directory location, evaluates some forms
and then restores the memorized location. Under CLISP, I have access
to the fchdir function. So I did it like this:

  (defmacro current-dir-restore (&body forms)
    (let ((saved-dir (gensym "SAVED-DIR-")))
      `(let ((,saved-dir (linux:open "." linux:O_RDONLY 0)))
	 (when (= ,saved-dir -1)
	   (error (make-condition 'open-error :path ".")))
	 (unwind-protect (progn ,@forms)
			 (fchdir ,saved-dir)
			 (linux:close ,saved-dir)))))

In other words, I open the directory as a file descriptor,
and bind that descriptor to a gensym'ed variable. I couldn't find
fchdir in CMUCL's UNIX package (hey, who would ever need fchdir, right?)
So I preserve the current directory as a full pathname string instead,
obtained via unix:unix-current-directory:

  (defmacro current-dir-restore (&body forms)
    (let ((saved-dir (gensym "SAVED-DIR-"))
	  (getdir-ok (gensym "GETDIR-OK-")))
      `(multiple-value-bind (,getdir-ok ,saved-dir)
			    (unix:unix-current-directory)
	 (when (not ,getdir-ok)
	   (error "could not determine current working directory"))
	 (unwind-protect (progn ,@forms)
			 (chdir ,saved-dir)))))

Different implementation, but the macro behaves the same way.  So that just
shows you that it takes a little bit of thought and work here and there
to access operating system functionality and try to sprinkle on enough
abstraction to keep it portable.
From: Paul D. Lathrop
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <uhnsobp1gnj79a@corp.supernews.com>
"Kaz Kylheku" <···@ashi.footprints.net> wrote in message
·················@luna.vcn.bc.ca...
> In article <··············@corp.supernews.com>, Paul D. Lathrop wrote:
> > I know this may be a completely newbie question, but please bear with
me. I
> > am writing some file-manipulation functions that I would find useful and
I
> > have run into a problem I cannot seem to find a method of using lisp to
> > delete directories. I have tried using 'delete-file' with the directory
> > pathname as an argument and I get
> >
> > Error: Failed to DELETE file D:/code/lisp/bleh/: 5: Access is denied.(5)
> >
> > Any chance someone out there can help me?
>
> If you want to do platform-specific file manipulation, you have to drop
> down a notch and access your operating system's service functions.
> There is no portable way to do this; Lisp systems have different
> FFI's (foreign function interfaces) and of course operating systems
> differ from each other as well. Some Lisp systems have a ready made
> package of system calls; see if yours has something like that.
>
> In Meta-CVS, I created a little layer which provides some POSIX functions
as
> Lisp functions; e.g. I can unlink a file using (unlink <pathname>), scan
> directories with (opendir ...) (readdir ...) and (closedir ...) and so on.
With
> some nice macros, a recursive directory deletion (analogous to the POSIX
> command ``rm -rf'') ends up looking very slick:
>
>   (defun delete-recursive (dir-or-file)
>     (for-each-file-info (fi dir-or-file :postorder t)
>       (if (directory-p fi)
>         (rmdir (file-name fi))
>         (unlink (file-name fi)))))
>
> It may help to remember that the ANSI C and C++ languages have no
directory
> deletion function either.  It's just that these languages make it far
easier to
> access the operating system specific functions, since the bindings to
these
> functions are already expressed in C. Not to mention that there is a class
of
> operating systems which share the same POSIX bindings. So you are only at
> a slight disadvantage in Lisp, due to having to deal with foreign function
> interfaces or system call packages that are incompatible among different
> Lisps.
>
> A good strategy is to identify what services you need and then write a
layer
> which provides these services. That layer can be retargetted to different
> Lisp systems. You can write a separate file for each Lisp system, or
> use #+ and #- feature tests to selectively read code.
>
> In Meta-CVS, I have a file called clisp-linux.lisp, and cmucl-unix.lisp.
> The latter is an ongoing, incomplete port to CMUCL. In clisp-linux.lisp
> (opendir ...) is defined like this:
>
>   (defun opendir (dir)
>     (cond
>       ((null-to-nil (linux:opendir dir)))
>       (t (error (make-condition 'open-dir-error :dir dir)))))
>
> This uses the LINUX package of glibc bindings that comes with CLISP
> and can be optionally built.
>
> In cmucl-unix.lisp, it looks like this:
>
>   (defun opendir (dir)
>     (cond
>       ((unix:open-dir dir))
>       (t (error (make-condition 'open-dir-error :dir dir)))))
>
> It's very similar, except for the spelling of open-dir, the package
> name, and that NIL is already returned if there is an error.
>
> A more interesting case study is my current-dir-restore macro which
> remembers the current working directory location, evaluates some forms
> and then restores the memorized location. Under CLISP, I have access
> to the fchdir function. So I did it like this:
>
>   (defmacro current-dir-restore (&body forms)
>     (let ((saved-dir (gensym "SAVED-DIR-")))
>       `(let ((,saved-dir (linux:open "." linux:O_RDONLY 0)))
> (when (= ,saved-dir -1)
>    (error (make-condition 'open-error :path ".")))
> (unwind-protect (progn ,@forms)
> (fchdir ,saved-dir)
> (linux:close ,saved-dir)))))
>
> In other words, I open the directory as a file descriptor,
> and bind that descriptor to a gensym'ed variable. I couldn't find
> fchdir in CMUCL's UNIX package (hey, who would ever need fchdir, right?)
> So I preserve the current directory as a full pathname string instead,
> obtained via unix:unix-current-directory:
>
>   (defmacro current-dir-restore (&body forms)
>     (let ((saved-dir (gensym "SAVED-DIR-"))
>   (getdir-ok (gensym "GETDIR-OK-")))
>       `(multiple-value-bind (,getdir-ok ,saved-dir)
>     (unix:unix-current-directory)
> (when (not ,getdir-ok)
>    (error "could not determine current working directory"))
> (unwind-protect (progn ,@forms)
> (chdir ,saved-dir)))))
>
> Different implementation, but the macro behaves the same way.  So that
just
> shows you that it takes a little bit of thought and work here and there
> to access operating system functionality and try to sprinkle on enough
> abstraction to keep it portable.

Many thanks. This was *extremely* helpful.

Paul
From: Roger Corman
Subject: Re: Deleting directories in lisp
Date: 
Message-ID: <3d239557.18644269@nntp.sonic.net>
On Fri, 28 Jun 2002 01:24:34 -0400, "Paul D. Lathrop"
<········@chartermi.net> wrote:

>"Kaz Kylheku" <···@ashi.footprints.net> wrote in message
>·················@luna.vcn.bc.ca...
>> In article <··············@corp.supernews.com>, Paul D. Lathrop wrote:
>> > I know this may be a completely newbie question, but please bear with
>me. I
>> > am writing some file-manipulation functions that I would find useful and
>I
>> > have run into a problem I cannot seem to find a method of using lisp to
>> > delete directories. I have tried using 'delete-file' with the directory
>> > pathname as an argument and I get
>> >

Here's some boilerplate code that show how to expose the delete
directory function in the Win32 API if you are using Corman Lisp:

(in-package :win32)
(defwinapi RemoveDirectory
	((lpPathName LPCSTR)) 
   :return-type BOOL
   :library-name "Kernel32"
   :entry-name "RemoveDirectoryA"
   :linkage-type :pascal)

(defun delete-directory (path)
    "Deletes an empty directory. 
     Returns true if successful, false otherwise."
    (win:RemoveDirectory 
        (ct:lisp-string-to-c-string (namestring (pathname path)))))
(export 'delete-directory)

This will allow you to use 
(win:delete-directory pathname)

to delete an empty directory. Obviously one could add more
bells and whistles.

Roger