unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* patch about moving file (or directory) to the Recycle Bin on Windows NT series
       [not found] ` <480CC2D7.3030302@gmail.com>
@ 2008-04-21 17:07   ` Toru TSUNEYOSHI
  0 siblings, 0 replies; 24+ messages in thread
From: Toru TSUNEYOSHI @ 2008-04-21 17:07 UTC (permalink / raw)
  To: emacs-devel; +Cc: Lennart Borgman (gmail)

[-- Attachment #1: Type: text/plain, Size: 170 bytes --]

I made a patch for src/{w32.c,emacs.c} (in emacs 22.2) about moving file
(or directory) to the Recycle Bin on Windows NT series.

If possible, please patch emacs source.

[-- Attachment #2: w32.c_and_emacs.c.diff --]
[-- Type: application/octet-stream, Size: 3356 bytes --]

--- w32.c.original	2008-02-23 22:49:09.000000000 +0900
+++ w32.c	2008-04-21 22:08:48.248179300 +0900
@@ -75,6 +75,10 @@
 #include <windows.h>
 #include <shlobj.h>
 
+#ifdef MYDEF
+#include <shellapi.h>
+#endif	/* MYDEF */
+
 #ifdef HAVE_SOCKETS	/* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
 #undef socket
@@ -111,6 +115,10 @@
 extern Lisp_Object Vw32_get_true_file_attributes;
 extern int w32_num_mouse_buttons;
 
+#ifdef MYDEF
+int w32_sys_unlink_use_shellapi;
+#endif	/* MYDEF */
+
 \f
 /*
   Initialization states
@@ -2240,6 +2248,71 @@
   return result;
 }
 
+#ifdef MYDEF
+
+int
+sys_rmdir (const char * path)
+{
+  if (w32_sys_unlink_use_shellapi)
+    return (sys_unlink ((const char *)path));
+  else
+    return _rmdir (map_w32_filename (path, NULL));
+}
+
+int
+sys_unlink (const char * path)
+{
+  if (w32_sys_unlink_use_shellapi)
+    {
+      /* Each file name must be terminated by a single NULL
+	 character. An additional NULL character must be appended to the
+	 end of the final name to indicate the end of pFrom. */
+      TCHAR tmp_path[MAX_PATH + 1 + 1];
+      SHFILEOPSTRUCT stFileOp;
+
+      path = map_w32_filename (path, NULL);
+
+      /* On Unix, unlink works without write permission. */
+      _chmod (path, 0666);
+
+#if 0
+      *(tmp_path + lstrlen(tmp_path) + 1) = '\0';
+#else
+      ZeroMemory(tmp_path, sizeof(tmp_path));
+#endif
+      lstrcpy(tmp_path, path);
+
+      ZeroMemory(&stFileOp, sizeof(SHFILEOPSTRUCT));
+      stFileOp.hwnd = HWND_DESKTOP;
+      stFileOp.wFunc = FO_DELETE;
+      stFileOp.pFrom = tmp_path;
+      stFileOp.pTo = NULL;
+      stFileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT;
+      stFileOp.fAnyOperationsAborted = FALSE;
+      stFileOp.hNameMappings = NULL;
+      stFileOp.lpszProgressTitle = NULL;
+
+#if 0
+      SHFileOperation(&stFileOp);
+
+      return (stFileOp.fAnyOperationsAborted);
+#else
+      /* value returned by SHFileOperation() must match value returned by _unlink() */
+      return (SHFileOperation(&stFileOp) == 0 ? 0 : -1);
+#endif
+    }
+  else
+    {
+      path = map_w32_filename (path, NULL);
+
+      /* On Unix, unlink works without write permission. */
+      _chmod (path, 0666);
+      return _unlink (path);
+    }
+}
+
+#else	/* MYDEF */
+
 int
 sys_rmdir (const char * path)
 {
@@ -2256,6 +2329,8 @@
   return _unlink (path);
 }
 
+#endif	/* MYDEF */
+
 static FILETIME utc_base_ft;
 static long double utc_base;
 static int init = 0;
@@ -4160,6 +4235,18 @@
   SetConsoleCtrlHandler(shutdown_handler, TRUE);
 }
 
+#ifdef MYDEF
+
+void
+syms_of_w32 ()
+{
+  DEFVAR_BOOL ("w32-sys-unlink-use-shellapi", &w32_sys_unlink_use_shellapi,
+	       "Non-nil means using shellapi for sys_unlink(), sys_rmdir().");
+  w32_sys_unlink_use_shellapi = 0;
+}
+
+#endif	/* MYDEF */
+
 /* end of w32.c */
 
 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
--- emacs.c.original	2008-01-10 21:16:14.000000000 +0900
+++ emacs.c	2008-04-21 22:14:55.457184200 +0900
@@ -1588,6 +1588,9 @@
       syms_of_vmsproc ();
 #endif /* VMS */
 #ifdef WINDOWSNT
+#ifdef MYDEF
+      syms_of_w32 ();
+#endif	/* MYDEF */
       syms_of_ntproc ();
 #endif /* WINDOWSNT */
       syms_of_window ();

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
@ 2008-04-21 21:32 Toru TSUNEYOSHI
  2008-04-22  9:02 ` Toru TSUNEYOSHI
                   ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: Toru TSUNEYOSHI @ 2008-04-21 21:32 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 44 bytes --]

I made a revised edition (including w32.h).

[-- Attachment #2: w32.h_w32.c_emacs.c.diff --]
[-- Type: application/octet-stream, Size: 4326 bytes --]

--- w32.h.original	2008-01-10 21:16:16.000000000 +0900
+++ w32.h	2008-04-22 05:52:24.056379500 +0900
@@ -129,6 +129,9 @@
 
 extern void init_ntproc (void);
 extern void term_ntproc (void);
+#ifdef W32_SYS_UNLINK_USE_SHELLAPI
+extern void syms_of_w32 (void);
+#endif /* W32_SYS_UNLINK_USE_SHELLAPI */
 extern void globals_of_w32 (void);
 extern void syms_of_w32term (void);
 extern void syms_of_w32fns (void);
--- w32.c.original	2008-02-23 22:49:09.000000000 +0900
+++ w32.c	2008-04-22 05:51:43.056197700 +0900
@@ -75,6 +75,10 @@
 #include <windows.h>
 #include <shlobj.h>
 
+#ifdef W32_SYS_UNLINK_USE_SHELLAPI
+#include <shellapi.h>
+#endif /* W32_SYS_UNLINK_USE_SHELLAPI */
+
 #ifdef HAVE_SOCKETS	/* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
 #undef socket
@@ -104,6 +108,9 @@
 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
   (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
 
+#ifdef W32_SYS_UNLINK_USE_SHELLAPI
+void syms_of_w32 ();
+#endif /* W32_SYS_UNLINK_USE_SHELLAPI */
 void globals_of_w32 ();
 
 extern Lisp_Object Vw32_downcase_file_names;
@@ -111,6 +118,10 @@
 extern Lisp_Object Vw32_get_true_file_attributes;
 extern int w32_num_mouse_buttons;
 
+#ifdef W32_SYS_UNLINK_USE_SHELLAPI
+int w32_sys_unlink_use_shellapi;
+#endif /* W32_SYS_UNLINK_USE_SHELLAPI */
+
 \f
 /*
   Initialization states
@@ -2240,6 +2251,71 @@
   return result;
 }
 
+#ifdef W32_SYS_UNLINK_USE_SHELLAPI
+
+int
+sys_rmdir (const char * path)
+{
+  if (w32_sys_unlink_use_shellapi)
+    return (sys_unlink ((const char *)path));
+  else
+    return _rmdir (map_w32_filename (path, NULL));
+}
+
+int
+sys_unlink (const char * path)
+{
+  if (w32_sys_unlink_use_shellapi)
+    {
+      /* Each file name must be terminated by a single NULL
+	 character. An additional NULL character must be appended to the
+	 end of the final name to indicate the end of pFrom. */
+      TCHAR tmp_path[MAX_PATH + 1 + 1];
+      SHFILEOPSTRUCT stFileOp;
+
+      path = map_w32_filename (path, NULL);
+
+      /* On Unix, unlink works without write permission. */
+      _chmod (path, 0666);
+
+#if 0
+      *(tmp_path + lstrlen(tmp_path) + 1) = '\0';
+#else
+      ZeroMemory(tmp_path, sizeof(tmp_path));
+#endif
+      lstrcpy(tmp_path, path);
+
+      ZeroMemory(&stFileOp, sizeof(SHFILEOPSTRUCT));
+      stFileOp.hwnd = HWND_DESKTOP;
+      stFileOp.wFunc = FO_DELETE;
+      stFileOp.pFrom = tmp_path;
+      stFileOp.pTo = NULL;
+      stFileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT;
+      stFileOp.fAnyOperationsAborted = FALSE;
+      stFileOp.hNameMappings = NULL;
+      stFileOp.lpszProgressTitle = NULL;
+
+#if 0
+      SHFileOperation(&stFileOp);
+
+      return (stFileOp.fAnyOperationsAborted);
+#else
+      /* value returned by SHFileOperation() must match value returned by _unlink() */
+      return (SHFileOperation(&stFileOp) == 0 ? 0 : -1);
+#endif
+    }
+  else
+    {
+      path = map_w32_filename (path, NULL);
+
+      /* On Unix, unlink works without write permission. */
+      _chmod (path, 0666);
+      return _unlink (path);
+    }
+}
+
+#else /* W32_SYS_UNLINK_USE_SHELLAPI */
+
 int
 sys_rmdir (const char * path)
 {
@@ -2256,6 +2332,8 @@
   return _unlink (path);
 }
 
+#endif /* W32_SYS_UNLINK_USE_SHELLAPI */
+
 static FILETIME utc_base_ft;
 static long double utc_base;
 static int init = 0;
@@ -4160,6 +4238,18 @@
   SetConsoleCtrlHandler(shutdown_handler, TRUE);
 }
 
+#ifdef W32_SYS_UNLINK_USE_SHELLAPI
+
+void
+syms_of_w32 ()
+{
+  DEFVAR_BOOL ("w32-sys-unlink-use-shellapi", &w32_sys_unlink_use_shellapi,
+	       "Non-nil means using shellapi for sys_unlink(), sys_rmdir().");
+  w32_sys_unlink_use_shellapi = 1;
+}
+
+#endif /* W32_SYS_UNLINK_USE_SHELLAPI */
+
 /* end of w32.c */
 
 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
--- emacs.c.original	2008-01-10 21:16:14.000000000 +0900
+++ emacs.c	2008-04-22 05:49:48.407912100 +0900
@@ -1588,6 +1588,9 @@
       syms_of_vmsproc ();
 #endif /* VMS */
 #ifdef WINDOWSNT
+#ifdef W32_SYS_UNLINK_USE_SHELLAPI
+      syms_of_w32 ();
+#endif /* W32_SYS_UNLINK_USE_SHELLAPI */
       syms_of_ntproc ();
 #endif /* WINDOWSNT */
       syms_of_window ();

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-21 21:32 patch about moving file (or directory) to the Recycle Bin on Windows NT series Toru TSUNEYOSHI
@ 2008-04-22  9:02 ` Toru TSUNEYOSHI
  2008-04-22 15:47   ` Stefan Monnier
  2008-04-22 18:19 ` Eli Zaretskii
  2008-04-23 15:35 ` Stefan Monnier
  2 siblings, 1 reply; 24+ messages in thread
From: Toru TSUNEYOSHI @ 2008-04-22  9:02 UTC (permalink / raw)
  To: emacs-devel

I wrote the reason for sending the patch.

I made it many years ago. I patched it every Emacs release.  But,
recently it's a bother.
And I have seen the QandA "Can move file to the Recycle Bin on Windows
NT series? => No" in (NT)Emacs (or Emacsen) FAQ, several times.
So, I sent it.
(I wish it is applied to Emacs source.)





^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-22  9:02 ` Toru TSUNEYOSHI
@ 2008-04-22 15:47   ` Stefan Monnier
  2008-04-22 17:04     ` Eli Zaretskii
  0 siblings, 1 reply; 24+ messages in thread
From: Stefan Monnier @ 2008-04-22 15:47 UTC (permalink / raw)
  To: Toru TSUNEYOSHI; +Cc: emacs-devel

> I wrote the reason for sending the patch.
> I made it many years ago. I patched it every Emacs release.  But,
> recently it's a bother.
> And I have seen the QandA "Can move file to the Recycle Bin on Windows
> NT series? => No" in (NT)Emacs (or Emacsen) FAQ, several times.
> So, I sent it.
> (I wish it is applied to Emacs source.)

Can someone here take a look at it, please?
It may not be the best solution (especially I'm thinking of what
happens with temp-files accumulating in the RecycleBin if `delete-file'
moves them there).  But some support might make sense.  Of course
similar support should be added for Gnome's trash can.


        Stefan




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-22 15:47   ` Stefan Monnier
@ 2008-04-22 17:04     ` Eli Zaretskii
  2008-04-22 18:24       ` Eli Zaretskii
  0 siblings, 1 reply; 24+ messages in thread
From: Eli Zaretskii @ 2008-04-22 17:04 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: t_tuneyosi, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Date: Tue, 22 Apr 2008 11:47:17 -0400
> Cc: emacs-devel@gnu.org
> 
> Can someone here take a look at it, please?

I will, if no one beats me to it.

> It may not be the best solution (especially I'm thinking of what
> happens with temp-files accumulating in the RecycleBin if `delete-file'
> moves them there).  But some support might make sense.

AFAICS, the patch makes it an optional feature.  As long as it's off
by default, I think it's okay.




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-21 21:32 patch about moving file (or directory) to the Recycle Bin on Windows NT series Toru TSUNEYOSHI
  2008-04-22  9:02 ` Toru TSUNEYOSHI
@ 2008-04-22 18:19 ` Eli Zaretskii
  2008-04-22 20:58   ` Jason Rumney
                     ` (2 more replies)
  2008-04-23 15:35 ` Stefan Monnier
  2 siblings, 3 replies; 24+ messages in thread
From: Eli Zaretskii @ 2008-04-22 18:19 UTC (permalink / raw)
  To: Toru TSUNEYOSHI; +Cc: emacs-devel

> From: "Toru TSUNEYOSHI" <t_tuneyosi@hotmail.com>
> Date: Tue, 22 Apr 2008 06:32:12 +0900
> 
> I made a revised edition (including w32.h).

Thank you.

I think this contribution is large enough to require legal papers, but
I'll let Stefan and Yidong decide that.

> +#ifdef W32_SYS_UNLINK_USE_SHELLAPI
> +extern void syms_of_w32 (void);
> +#endif /* W32_SYS_UNLINK_USE_SHELLAPI */

If we are going to support this feature, we don't need this
conditional compilation, so please remove the #ifdef's (here and
everywhere else).

> +  if (w32_sys_unlink_use_shellapi)
> +    {
> +      /* Each file name must be terminated by a single NULL
> +	 character. An additional NULL character must be appended to the
> +	 end of the final name to indicate the end of pFrom. */
> +      TCHAR tmp_path[MAX_PATH + 1 + 1];

AFAIU from the Microsoft documentation, there's no need for the second
"+1", as MAX_PATH already accounts for one terminating null character.

> +      SHFILEOPSTRUCT stFileOp;
> +
> +      path = map_w32_filename (path, NULL);

MSDN advises to use only absolute file names with SHFileOperation,
otherwise they say that recycling will not work (see
http://msdn2.microsoft.com/en-us/library/bb759795(VS.85).aspx for the
details). So I think we need to make the file name absolute here.

> +      /* On Unix, unlink works without write permission. */
> +      _chmod (path, 0666);

Can this somehow leave the file writable without deleting it, if the
code is interrupted before it gets to undo this _chmod call?  If so,
we need to guard against that somehow.

> +      ZeroMemory(&stFileOp, sizeof(SHFILEOPSTRUCT));
> +      stFileOp.hwnd = HWND_DESKTOP;
> +      stFileOp.wFunc = FO_DELETE;
> +      stFileOp.pFrom = tmp_path;
> +      stFileOp.pTo = NULL;
> +      stFileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT;

Do we want to use the FOF_NO_CONNECTED_ELEMENTS flag here?  Deleting
connected files, which is the default with shell API, is not what
happens with the normal unlink, is it?  So it might surprise the user
if we do that when using the shell API.

How about FOF_NOERRORUI? do we want it?  I understand that without it,
a dialog will be presented to the user in case of any errors during
the deletion.

> +      /* value returned by SHFileOperation() must match value returned by _unlink() */
> +      return (SHFileOperation(&stFileOp) == 0 ? 0 : -1);

Do we want to set errno here, at least for some popular reasons that
fail the deletion, using the DE_* error codes documented on the MSDN?
The caller of this function may wish to look at errno and provide
diagnostics.

> +void
> +syms_of_w32 ()
> +{
> +  DEFVAR_BOOL ("w32-sys-unlink-use-shellapi", &w32_sys_unlink_use_shellapi,
> +	       "Non-nil means using shellapi for sys_unlink(), sys_rmdir().");
> +  w32_sys_unlink_use_shellapi = 1;
> +}

Please use a more descriptive name, such as w32-delete-to-recycle-bin
or something similar.  The point is that the name should tell a user
what this option will do, not which API it will use.  (I imagine that
many Emacs users don't even know what is the shell API.)

Also, please make this option off by default.

In addition, we need an entry for NEWS about this new feature.  Could
you please write it?

Finally, using this feature requires to add -lshellapi to the linker
switches in nt/?make.defs, right?  Or is that linked in by default?

Thanks again for working on this.




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-22 17:04     ` Eli Zaretskii
@ 2008-04-22 18:24       ` Eli Zaretskii
  0 siblings, 0 replies; 24+ messages in thread
From: Eli Zaretskii @ 2008-04-22 18:24 UTC (permalink / raw)
  To: monnier, t_tuneyosi, emacs-devel

> Date: Tue, 22 Apr 2008 20:04:28 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> Cc: t_tuneyosi@hotmail.com, emacs-devel@gnu.org
> 
> > From: Stefan Monnier <monnier@iro.umontreal.ca>
> > Date: Tue, 22 Apr 2008 11:47:17 -0400
> > Cc: emacs-devel@gnu.org
> > 
> > Can someone here take a look at it, please?
> 
> I will, if no one beats me to it.

Done.




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-22 18:19 ` Eli Zaretskii
@ 2008-04-22 20:58   ` Jason Rumney
  2008-04-23  1:15     ` Stefan Monnier
  2008-04-23  1:14   ` Stefan Monnier
  2008-04-23 16:45   ` Toru TSUNEYOSHI
  2 siblings, 1 reply; 24+ messages in thread
From: Jason Rumney @ 2008-04-22 20:58 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Toru TSUNEYOSHI, emacs-devel

Eli Zaretskii wrote:
>> +void
>> +syms_of_w32 ()
>> +{
>> +  DEFVAR_BOOL ("w32-sys-unlink-use-shellapi", &w32_sys_unlink_use_shellapi,
>> +	       "Non-nil means using shellapi for sys_unlink(), sys_rmdir().");
>> +  w32_sys_unlink_use_shellapi = 1;
>> +}
>>     
>
> Please use a more descriptive name, such as w32-delete-to-recycle-bin
> or something similar.

I would go further, and define it without the w32_ prefix in fileio.c 
with a suitable #ifdef (HAVE_TRASHCAN for example).  If this feature is 
useful, then we will want to implement it on other platforms too. There 
seem to be a limited number of Trash directory implementations that 
cover Gnome, KDE and Mac OSX, and we should be able to figure out from 
the filesystem which implementation to use, either directly moving files 
into the .Trash directory, or calling a function like g_file_trash if 
the appropriate library is linked.





^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-22 18:19 ` Eli Zaretskii
  2008-04-22 20:58   ` Jason Rumney
@ 2008-04-23  1:14   ` Stefan Monnier
  2008-04-23  4:55     ` Eli Zaretskii
  2008-04-23 16:45   ` Toru TSUNEYOSHI
  2 siblings, 1 reply; 24+ messages in thread
From: Stefan Monnier @ 2008-04-23  1:14 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Toru TSUNEYOSHI, emacs-devel

>> +      /* On Unix, unlink works without write permission. */
>> +      _chmod (path, 0666);

> Can this somehow leave the file writable without deleting it, if the
> code is interrupted before it gets to undo this _chmod call?  If so,
> we need to guard against that somehow.

Also that makes the file temporarily readable/writable by everybody.
It's probably better to set it to 0600.  Of course, maybe this is
irrelevant because of the way w32 interprets those
Unix-style permissions.


        Stefan




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-22 20:58   ` Jason Rumney
@ 2008-04-23  1:15     ` Stefan Monnier
  0 siblings, 0 replies; 24+ messages in thread
From: Stefan Monnier @ 2008-04-23  1:15 UTC (permalink / raw)
  To: Jason Rumney; +Cc: Eli Zaretskii, Toru TSUNEYOSHI, emacs-devel

> I would go further, and define it without the w32_ prefix in fileio.c with
> a suitable #ifdef (HAVE_TRASHCAN for example).  If this feature is useful,
> then we will want to implement it on other platforms too. There seem to be
> a limited number of Trash directory implementations that cover Gnome, KDE
> and Mac OSX, and we should be able to figure out from the filesystem which
> implementation to use, either directly moving files into the .Trash
> directory, or calling a function like g_file_trash if the appropriate
> library is linked.

Agreed,


        Stefan




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-23  1:14   ` Stefan Monnier
@ 2008-04-23  4:55     ` Eli Zaretskii
  0 siblings, 0 replies; 24+ messages in thread
From: Eli Zaretskii @ 2008-04-23  4:55 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: t_tuneyosi, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Toru TSUNEYOSHI <t_tuneyosi@hotmail.com>,  emacs-devel@gnu.org
> Date: Tue, 22 Apr 2008 21:14:30 -0400
> 
> >> +      /* On Unix, unlink works without write permission. */
> >> +      _chmod (path, 0666);
> 
> > Can this somehow leave the file writable without deleting it, if the
> > code is interrupted before it gets to undo this _chmod call?  If so,
> > we need to guard against that somehow.
> 
> Also that makes the file temporarily readable/writable by everybody.
> It's probably better to set it to 0600.  Of course, maybe this is
> irrelevant because of the way w32 interprets those
> Unix-style permissions.

Yes, 0600 and 0666 are the same on Windows.  When using the Posix
emulation functions, such as _chmod, there's only 1 bit that describes
whether the file is writable or not.

If we really care about this, we need to use the security API, where a
full-blown ACL functionality is available.

Alternatively, we could simply let the call fail for files not
writable by the user: after all, this is what the Windows Explorer
will do when you delete files through it.




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-21 21:32 patch about moving file (or directory) to the Recycle Bin on Windows NT series Toru TSUNEYOSHI
  2008-04-22  9:02 ` Toru TSUNEYOSHI
  2008-04-22 18:19 ` Eli Zaretskii
@ 2008-04-23 15:35 ` Stefan Monnier
  2008-04-25 20:18   ` Toru TSUNEYOSHI
  2 siblings, 1 reply; 24+ messages in thread
From: Stefan Monnier @ 2008-04-23 15:35 UTC (permalink / raw)
  To: Toru TSUNEYOSHI; +Cc: emacs-devel

> I made a revised edition (including w32.h).

I suggest we use a slightly different interface:
1 - Implement a new Elisp function `move-file-to-trash'.
2 - Add a config variable `delete-by-moving-to-trash' (default to nil).

The implementation of delete-by-moving-to-trash will at first be naive:
if set, delete-file delegates the job to move-file-to-trash.


        Stefan


PS: We will probably want to refine this implementation at some point so
that only some uses of delete-file are redirected to move-file-to-trash,
but let's start with that.




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-22 18:19 ` Eli Zaretskii
  2008-04-22 20:58   ` Jason Rumney
  2008-04-23  1:14   ` Stefan Monnier
@ 2008-04-23 16:45   ` Toru TSUNEYOSHI
  2 siblings, 0 replies; 24+ messages in thread
From: Toru TSUNEYOSHI @ 2008-04-23 16:45 UTC (permalink / raw)
  To: emacs-devel; +Cc: Eli Zaretskii

[-- Attachment #1: Type: text/plain, Size: 4890 bytes --]

Thanks, everyone, especially Eli Zaretskii.

Just Now I checked new suggestion from Stefan Monnier.
But I have already fixed as follows, I will send it.

----- Original Message ----- 
From: "Eli Zaretskii" <eliz@gnu.org>
To: "Toru TSUNEYOSHI" <t_tuneyosi@hotmail.com>
Cc: <emacs-devel@gnu.org>
Sent: Wednesday, April 23, 2008 3:19 AM
Subject: Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series

> > From: "Toru TSUNEYOSHI" <t_tuneyosi@hotmail.com>
> > Date: Tue, 22 Apr 2008 06:32:12 +0900
> > 
> > I made a revised edition (including w32.h).
> 
> Thank you.
> 
> I think this contribution is large enough to require legal papers, but
> I'll let Stefan and Yidong decide that.
> 

You are welcome.

> > +#ifdef W32_SYS_UNLINK_USE_SHELLAPI
> > +extern void syms_of_w32 (void);
> > +#endif /* W32_SYS_UNLINK_USE_SHELLAPI */
> 
> If we are going to support this feature, we don't need this
> conditional compilation, so please remove the #ifdef's (here and
> everywhere else).
> 

I removed all of them.

> > +  if (w32_sys_unlink_use_shellapi)
> > +    {
> > +      /* Each file name must be terminated by a single NULL
> > + character. An additional NULL character must be appended to the
> > + end of the final name to indicate the end of pFrom. */
> > +      TCHAR tmp_path[MAX_PATH + 1 + 1];
> 
> AFAIU from the Microsoft documentation, there's no need for the second
> "+1", as MAX_PATH already accounts for one terminating null character.
> 

Oops. You are right. I fixed it.

> > +      SHFILEOPSTRUCT stFileOp;
> > +
> > +      path = map_w32_filename (path, NULL);
> 
> MSDN advises to use only absolute file names with SHFileOperation,
> otherwise they say that recycling will not work (see
> http://msdn2.microsoft.com/en-us/library/bb759795(VS.85).aspx for the
> details). So I think we need to make the file name absolute here.
> 

Yes, I added statements for it.

> > +      /* On Unix, unlink works without write permission. */
> > +      _chmod (path, 0666);
> 
> Can this somehow leave the file writable without deleting it, if the
> code is interrupted before it gets to undo this _chmod call?  If so,
> we need to guard against that somehow.
> 

I don't know what to do about it. So, I do nothing.

> > +      ZeroMemory(&stFileOp, sizeof(SHFILEOPSTRUCT));
> > +      stFileOp.hwnd = HWND_DESKTOP;
> > +      stFileOp.wFunc = FO_DELETE;
> > +      stFileOp.pFrom = tmp_path;
> > +      stFileOp.pTo = NULL;
> > +      stFileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT;
> 
> Do we want to use the FOF_NO_CONNECTED_ELEMENTS flag here?  Deleting
> connected files, which is the default with shell API, is not what
> happens with the normal unlink, is it?  So it might surprise the user
> if we do that when using the shell API.
> 

OK, I added it. And, I build Emacs by MS VC++ 6.0. SHELLAPI.H in MS VC++
6.0 don't include `FOF_NO_CONNECTED_ELEMENTS', so I added it to w32.c.

> How about FOF_NOERRORUI? do we want it?  I understand that without it,
> a dialog will be presented to the user in case of any errors during
> the deletion.
> 

Yes, I added it.

> > +      /* value returned by SHFileOperation() must match value returned by _unlink() */
> > +      return (SHFileOperation(&stFileOp) == 0 ? 0 : -1);
> 
> Do we want to set errno here, at least for some popular reasons that
> fail the deletion, using the DE_* error codes documented on the MSDN?
> The caller of this function may wish to look at errno and provide
> diagnostics.
> 

I don't know what to do about it, because the caller of this function
may assume that _unlink() or _rmdir() returns 0 or -1 in the existing
code.

> > +void
> > +syms_of_w32 ()
> > +{
> > +  DEFVAR_BOOL ("w32-sys-unlink-use-shellapi", &w32_sys_unlink_use_shellapi,
> > +        "Non-nil means using shellapi for sys_unlink(), sys_rmdir().");
> > +  w32_sys_unlink_use_shellapi = 1;
> > +}
> 
> Please use a more descriptive name, such as w32-delete-to-recycle-bin
> or something similar.  The point is that the name should tell a user
> what this option will do, not which API it will use.  (I imagine that
> many Emacs users don't even know what is the shell API.)
> 
> Also, please make this option off by default.
> 

I fixed it as you wrote.

> In addition, we need an entry for NEWS about this new feature.  Could
> you please write it?
> 

Yes, I wrote it. But I don't know document format for NEWS, so I
followed examples in etc/NEWS.

> Finally, using this feature requires to add -lshellapi to the linker
> switches in nt/?make.defs, right?  Or is that linked in by default?
> 

It already existed.

There is variable SHELL32 in nt/nmake.defs.
SHELL32  = shell32.lib

There is variable SHELL32 in nt/gmake.defs
SHELL32  = -lshell32

And, varialbe LIBS in src/makefile.w32-in includes variable SHELL32.

> Thanks again for working on this.
> 

Thanks a lot for your helping.

[-- Attachment #2: w32.h_w32.c_emacs.c.diff --]
[-- Type: application/octet-stream, Size: 4002 bytes --]

--- src/w32.h.original	2008-01-10 21:16:16.000000000 +0900
+++ src/w32.h	2008-04-24 00:44:33.769063800 +0900
@@ -129,6 +129,7 @@
 
 extern void init_ntproc (void);
 extern void term_ntproc (void);
+extern void syms_of_w32 (void);
 extern void globals_of_w32 (void);
 extern void syms_of_w32term (void);
 extern void syms_of_w32fns (void);
--- src/w32.c.original	2008-02-23 22:49:09.000000000 +0900
+++ src/w32.c	2008-04-24 00:42:22.761991200 +0900
@@ -75,6 +75,11 @@
 #include <windows.h>
 #include <shlobj.h>
 
+#include <shellapi.h>
+#ifndef FOF_NO_CONNECTED_ELEMENTS
+#define FOF_NO_CONNECTED_ELEMENTS 0x2000 /* don't operate on connected elements. */
+#endif /* FOF_NO_CONNECTED_ELEMENTS */
+
 #ifdef HAVE_SOCKETS	/* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
 #undef socket
@@ -104,6 +109,7 @@
 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
   (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
 
+void syms_of_w32 ();
 void globals_of_w32 ();
 
 extern Lisp_Object Vw32_downcase_file_names;
@@ -111,6 +117,8 @@
 extern Lisp_Object Vw32_get_true_file_attributes;
 extern int w32_num_mouse_buttons;
 
+int w32_delete_to_recycle_bin;
+
 \f
 /*
   Initialization states
@@ -2243,17 +2251,58 @@
 int
 sys_rmdir (const char * path)
 {
-  return _rmdir (map_w32_filename (path, NULL));
+  if (w32_delete_to_recycle_bin)
+    return (sys_unlink (path));
+  else
+    return _rmdir (map_w32_filename (path, NULL));
 }
 
 int
 sys_unlink (const char * path)
 {
-  path = map_w32_filename (path, NULL);
+  if (w32_delete_to_recycle_bin)
+    {
+      SHFILEOPSTRUCT file_op;
+      /* `pFrom' member of struct SHFILEOPSTRUCT:
+	 Each file name must be terminated by a single NULL
+	 character. An additional NULL character must be appended to the
+	 end of the final name to indicate the end of pFrom. */
+      char tmp_path[MAX_PATH + 1];
+      Lisp_Object tmp;
+
+      /* Must use only absolute file names with SHFileOperation(). */
+      tmp = Fexpand_file_name (build_string (path), Qnil);
+
+      path = map_w32_filename (SDATA (tmp), NULL);
+
+      /* On Unix, unlink works without write permission. */
+      _chmod (path, 0666);
+
+      memset (tmp_path, 0, sizeof (tmp_path));
+      strcpy(tmp_path, path);
+
+      memset(&file_op, 0, sizeof (file_op));
+      file_op.hwnd = HWND_DESKTOP;
+      file_op.wFunc = FO_DELETE;
+      file_op.pFrom = tmp_path;
+      file_op.pTo = NULL;
+      file_op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
+	| FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
+      file_op.fAnyOperationsAborted = FALSE;
+      file_op.hNameMappings = NULL;
+      file_op.lpszProgressTitle = NULL;
+
+      /* value returned by SHFileOperation() must match value returned by _unlink() */
+      return (SHFileOperation(&file_op) == 0 ? 0 : -1);
+    }
+  else
+    {
+      path = map_w32_filename (path, NULL);
 
-  /* On Unix, unlink works without write permission. */
-  _chmod (path, 0666);
-  return _unlink (path);
+      /* On Unix, unlink works without write permission. */
+      _chmod (path, 0666);
+      return _unlink (path);
+    }
 }
 
 static FILETIME utc_base_ft;
@@ -4160,6 +4209,16 @@
   SetConsoleCtrlHandler(shutdown_handler, TRUE);
 }
 
+void
+syms_of_w32 ()
+{
+  DEFVAR_BOOL ("w32-delete-to-recycle-bin",
+	       &w32_delete_to_recycle_bin,
+	       doc: /* Non-nil means delete file or directory to recycle bin.
+Default is nil, which means just delete it.  */);
+  w32_delete_to_recycle_bin = 0;
+}
+
 /* end of w32.c */
 
 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
--- src/emacs.c.original	2008-01-10 21:16:14.000000000 +0900
+++ src/emacs.c	2008-04-24 00:43:32.060947200 +0900
@@ -1588,6 +1588,7 @@
       syms_of_vmsproc ();
 #endif /* VMS */
 #ifdef WINDOWSNT
+      syms_of_w32 ();
       syms_of_ntproc ();
 #endif /* WINDOWSNT */
       syms_of_window ();

[-- Attachment #3: NEWS --]
[-- Type: application/octet-stream, Size: 283 bytes --]

** Deleting files to the Recycle Bin is now supported on MS Windows.

Now Emacs can delete files or directories to the Recycle Bin on MS
Windows.
This feature is disabled by default. To enable it, put

  (setq w32-delete-to-recycle-bin t)

in your .emacs or some other startup file.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-23 15:35 ` Stefan Monnier
@ 2008-04-25 20:18   ` Toru TSUNEYOSHI
  0 siblings, 0 replies; 24+ messages in thread
From: Toru TSUNEYOSHI @ 2008-04-25 20:18 UTC (permalink / raw)
  To: emacs-devel; +Cc: Stefan Monnier

[-- Attachment #1: Type: text/plain, Size: 1227 bytes --]

Now I made new patch for function move-file-to-trash (maybe as you
wrote).

step to enable move-file-to-trash:

    cd src
    patch -i patch__enable_delete_to_trash.diff
    make all install

    Run emacs
    (load-file "move-file-to-trash.el")
    (setq delete-by-moving-to-trash t)

I think it is useful. And I wish that someone else improve the code.

----- Original Message ----- 
From: "Stefan Monnier" <monnier@iro.umontreal.ca>
To: "Toru TSUNEYOSHI" <t_tuneyosi@hotmail.com>
Cc: <emacs-devel@gnu.org>
Sent: Thursday, April 24, 2008 12:35 AM
Subject: Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series


> > I made a revised edition (including w32.h).
> 
> I suggest we use a slightly different interface:
> 1 - Implement a new Elisp function `move-file-to-trash'.
> 2 - Add a config variable `delete-by-moving-to-trash' (default to nil).
> 
> The implementation of delete-by-moving-to-trash will at first be naive:
> if set, delete-file delegates the job to move-file-to-trash.
> 
> 
>         Stefan
> 
> 
> PS: We will probably want to refine this implementation at some point so
> that only some uses of delete-file are redirected to move-file-to-trash,
> but let's start with that.

[-- Attachment #2: move-file-to-trash.el --]
[-- Type: application/octet-stream, Size: 2134 bytes --]

;; moved to C source code
;;
;;	(defvar delete-by-moving-to-trash nil
;;	  "Non nil means redirect to `move-file-to-trash'
;;	by `delete-file' or `delete-directory'")

(or (functionp 'orig-backup-extract-version)
    (fset 'orig-backup-extract-version (symbol-function 'backup-extract-version)))
;; Note: The following function can deal with directory properly.
(defun backup-extract-version (fn)
  "Given the name of a numeric backup file, return the backup number.
Uses the free variable `backup-extract-version-start', whose value should be
the index in the name where the version number begins."
  (if (and (string-match "[0-9]+~/?$" fn backup-extract-version-start)
	   (= (match-beginning 0) backup-extract-version-start))
      (string-to-int (substring fn backup-extract-version-start -1))
      0))

(defvar trash-directory "~/.trash"
  "Trash directory to move file (or directory) by `move-file-to-trash',
when system-specific move-file-to-trash doesn't exist.
If set \".trash\", always move to the directory under default-directory.
See also `delete-by-moving-to-trash'.")

(defun move-file-to-trash (filename)
  "Move file (or directory) named FILENAME.
Usually this function is called by `delete-file' or `delete-directory',
so must return nil if succeed."
  (interactive "fMove file to trash: ")
  (cond
   ((eq system-type 'windows-nt)
    (w32-move-file-to-trash filename))
   (t
    (let* ((trash-dir	(expand-file-name trash-directory))
	   (fn		(directory-file-name (expand-file-name filename)))
	   (fn-nondir	(file-name-nondirectory fn))
	   (new-fn	(expand-file-name fn-nondir trash-dir)))
      (or (file-directory-p trash-dir)
	  (make-directory trash-dir t))
      (when (file-exists-p new-fn)
	;; change unique new-fn.
	;; example: "~/.trash/abc.txt" -> "~/.trash/abc.txt.~1~"
	(let ((version-control t))
	  (setq new-fn (car (find-backup-file-name new-fn)))))
      ;; stop processing if fn is same or parent directory of trash-dir.
      (and (string-match fn trash-dir)
	   (error (message "filename `%s' is same or parent directory of trash-directory."
			   filename)))
      (rename-file fn new-fn)))))

[-- Attachment #3: patch__enable_delete_to_trash.diff --]
[-- Type: application/octet-stream, Size: 5755 bytes --]

--- src/emacs.c.original	2008-01-10 21:16:14.000000000 +0900
+++ src/emacs.c	2008-04-26 00:44:31.382475200 +0900
@@ -1588,6 +1588,7 @@
       syms_of_vmsproc ();
 #endif /* VMS */
 #ifdef WINDOWSNT
+      syms_of_w32 ();
       syms_of_ntproc ();
 #endif /* WINDOWSNT */
       syms_of_window ();
--- src/fileio.c.original	2008-03-11 10:56:52.000000000 +0900
+++ src/fileio.c	2008-04-25 22:32:53.391973600 +0900
@@ -231,6 +231,13 @@
 int write_region_inhibit_fsync;
 #endif
 
+/* Nonzero means call move-file-to-trash in Fdelete_file or
+   Fdelete_directory.  */
+int delete_by_moving_to_trash;
+
+/* Lisp functions for move file to trash */
+Lisp_Object Qmove_file_to_trash;
+
 extern Lisp_Object Vuser_login_name;
 
 #ifdef WINDOWSNT
@@ -2669,6 +2676,9 @@
   if (!NILP (handler))
     return call2 (handler, Qdelete_directory, directory);
 
+  if (delete_by_moving_to_trash)
+    return call1 (Qmove_file_to_trash, directory);
+
   encoded_dir = ENCODE_FILE (directory);
 
   dir = SDATA (encoded_dir);
@@ -2702,6 +2712,9 @@
   if (!NILP (handler))
     return call2 (handler, Qdelete_file, filename);
 
+  if (delete_by_moving_to_trash)
+    return call1 (Qmove_file_to_trash, filename);
+
   encoded_file = ENCODE_FILE (filename);
 
   if (0 > unlink (SDATA (encoded_file)))
@@ -6757,6 +6770,13 @@
   write_region_inhibit_fsync = 0;
 #endif
 
+  DEFVAR_BOOL ("delete-by-moving-to-trash", &delete_by_moving_to_trash,
+	       doc: /* Non-nil means redirect to `move-file-to-trash'
+by `delete-file' or `delete-directory'.  */);
+  delete_by_moving_to_trash = 0;
+  Qmove_file_to_trash = intern ("move-file-to-trash");
+  staticpro (&Qmove_file_to_trash);
+
   defsubr (&Sfind_file_name_handler);
   defsubr (&Sfile_name_directory);
   defsubr (&Sfile_name_nondirectory);
--- src/lisp.h.original	2008-01-10 21:16:15.000000000 +0900
+++ src/lisp.h	2008-04-25 23:50:59.844510400 +0900
@@ -2898,6 +2898,8 @@
 extern void init_fileio_once P_ ((void));
 extern Lisp_Object make_temp_name P_ ((Lisp_Object, int));
 EXFUN (Fmake_symbolic_link, 3);
+extern Lisp_Object Qdelete_directory;
+extern Lisp_Object Qdelete_file;
 
 /* Defined in abbrev.c */
 
--- src/w32.c.original	2008-02-23 22:49:09.000000000 +0900
+++ src/w32.c	2008-04-26 03:33:03.212572800 +0900
@@ -75,6 +75,11 @@
 #include <windows.h>
 #include <shlobj.h>
 
+#include <shellapi.h>
+#ifndef FOF_NO_CONNECTED_ELEMENTS
+#define FOF_NO_CONNECTED_ELEMENTS 0x2000 /* don't operate on connected elements. */
+#endif /* FOF_NO_CONNECTED_ELEMENTS */
+
 #ifdef HAVE_SOCKETS	/* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
 #undef socket
@@ -96,6 +101,8 @@
 #undef sendto
 #endif
 
+#include "charset.h"
+#include "coding.h"
 #include "w32.h"
 #include "ndir.h"
 #include "w32heap.h"
@@ -104,6 +111,7 @@
 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
   (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
 
+void syms_of_w32 ();
 void globals_of_w32 ();
 
 extern Lisp_Object Vw32_downcase_file_names;
@@ -2256,6 +2264,64 @@
   return _unlink (path);
 }
 
+/* deverted from delete-file in fileio.c */
+DEFUN ("w32-move-file-to-trash", Fw32_move_file_to_trash,
+       Sw32_move_file_to_trash, 1, 1, "fMove file to trash: ",
+       doc: /* Move file (or direcotry) named FILENAME.  */)
+     (filename)
+     Lisp_Object filename;
+{
+  Lisp_Object handler;
+  Lisp_Object encoded_file;
+  Lisp_Object operation;
+
+  operation = Qdelete_file;
+  if (!NILP (Ffile_directory_p (filename))
+      && NILP (Ffile_symlink_p (filename)))
+    operation = Qdelete_directory;
+  filename = Fexpand_file_name (filename, Qnil);
+
+  handler = Ffind_file_name_handler (filename, operation);
+  if (!NILP (handler))
+    return call2 (handler, operation, filename);
+
+  encoded_file = ENCODE_FILE (filename);
+
+  {
+    const char * path;
+    SHFILEOPSTRUCT file_op;
+    /* `pFrom' member of struct SHFILEOPSTRUCT:
+       Each file name must be terminated by a single NULL
+       character. An additional NULL character must be appended to the
+       end of the final name to indicate the end of pFrom. */
+    char tmp_path[MAX_PATH + 1];
+
+    path = map_w32_filename (SDATA (encoded_file), NULL);
+
+    /* On Unix, unlink works without write permission. */
+    _chmod (path, 0666);
+
+    memset (tmp_path, 0, sizeof (tmp_path));
+    strcpy (tmp_path, path);
+
+    memset (&file_op, 0, sizeof (file_op));
+    file_op.hwnd = HWND_DESKTOP;
+    file_op.wFunc = FO_DELETE;
+    file_op.pFrom = tmp_path;
+    file_op.pTo = NULL;
+    file_op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
+      | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
+    file_op.fAnyOperationsAborted = FALSE;
+    file_op.hNameMappings = NULL;
+    file_op.lpszProgressTitle = NULL;
+
+    if (SHFileOperation (&file_op) != 0)
+      report_file_error ("Removing old name", list1 (filename));
+  }
+
+  return Qnil;
+}
+
 static FILETIME utc_base_ft;
 static long double utc_base;
 static int init = 0;
@@ -4140,6 +4206,12 @@
   return FALSE;
 }
 
+void
+syms_of_w32 ()
+{
+  defsubr (&Sw32_move_file_to_trash);
+}
+
 /*
 	globals_of_w32 is used to initialize those global variables that
 	must always be initialized on startup even when the global variable
--- src/w32.h.original	2008-01-10 21:16:16.000000000 +0900
+++ src/w32.h	2008-04-26 00:43:48.961476800 +0900
@@ -129,6 +129,7 @@
 
 extern void init_ntproc (void);
 extern void term_ntproc (void);
+extern void syms_of_w32 (void);
 extern void globals_of_w32 (void);
 extern void syms_of_w32term (void);
 extern void syms_of_w32fns (void);

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
@ 2008-04-25 21:10 Toru TSUNEYOSHI
  2008-04-26  7:25 ` Eli Zaretskii
  2008-05-25  1:24 ` Stefan Monnier
  0 siblings, 2 replies; 24+ messages in thread
From: Toru TSUNEYOSHI @ 2008-04-25 21:10 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 960 bytes --]

A bug was function w32-move-file-to-trash in w32.c

example: ("~/test" is directory)

    (w32-move-file-to-trash "~/test")
    => ok
    (w32-move-file-to-trash "~/test/")
    => error


So I fixed it.

    (w32-move-file-to-trash "~/test/")
    => ok

Please use this patch not old one.

----- Original Message ----- 
From: "Toru TSUNEYOSHI" <t_tuneyosi@hotmail.com>
To: <emacs-devel@gnu.org>
Cc: "Stefan Monnier" <monnier@iro.umontreal.ca>
Sent: Saturday, April 26, 2008 5:18 AM
Subject: Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series


> Now I made new patch for function move-file-to-trash (maybe as you
> wrote).
> 
> step to enable move-file-to-trash:
> 
>     cd src
>     patch -i patch__enable_delete_to_trash.diff
>     make all install
> 
>     Run emacs
>     (load-file "move-file-to-trash.el")
>     (setq delete-by-moving-to-trash t)
> 
> I think it is useful. And I wish that someone else improve the code.

[-- Attachment #2: move-file-to-trash.el --]
[-- Type: application/octet-stream, Size: 2134 bytes --]

;; moved to C source code
;;
;;	(defvar delete-by-moving-to-trash nil
;;	  "Non nil means redirect to `move-file-to-trash'
;;	by `delete-file' or `delete-directory'")

(or (functionp 'orig-backup-extract-version)
    (fset 'orig-backup-extract-version (symbol-function 'backup-extract-version)))
;; Note: The following function can deal with directory properly.
(defun backup-extract-version (fn)
  "Given the name of a numeric backup file, return the backup number.
Uses the free variable `backup-extract-version-start', whose value should be
the index in the name where the version number begins."
  (if (and (string-match "[0-9]+~/?$" fn backup-extract-version-start)
	   (= (match-beginning 0) backup-extract-version-start))
      (string-to-int (substring fn backup-extract-version-start -1))
      0))

(defvar trash-directory "~/.trash"
  "Trash directory to move file (or directory) by `move-file-to-trash',
when system-specific move-file-to-trash doesn't exist.
If set \".trash\", always move to the directory under default-directory.
See also `delete-by-moving-to-trash'.")

(defun move-file-to-trash (filename)
  "Move file (or directory) named FILENAME.
Usually this function is called by `delete-file' or `delete-directory',
so must return nil if succeed."
  (interactive "fMove file to trash: ")
  (cond
   ((eq system-type 'windows-nt)
    (w32-move-file-to-trash filename))
   (t
    (let* ((trash-dir	(expand-file-name trash-directory))
	   (fn		(directory-file-name (expand-file-name filename)))
	   (fn-nondir	(file-name-nondirectory fn))
	   (new-fn	(expand-file-name fn-nondir trash-dir)))
      (or (file-directory-p trash-dir)
	  (make-directory trash-dir t))
      (when (file-exists-p new-fn)
	;; change unique new-fn.
	;; example: "~/.trash/abc.txt" -> "~/.trash/abc.txt.~1~"
	(let ((version-control t))
	  (setq new-fn (car (find-backup-file-name new-fn)))))
      ;; stop processing if fn is same or parent directory of trash-dir.
      (and (string-match fn trash-dir)
	   (error (message "filename `%s' is same or parent directory of trash-directory."
			   filename)))
      (rename-file fn new-fn)))))

[-- Attachment #3: patch__enable_delete_to_trash.diff --]
[-- Type: application/octet-stream, Size: 5811 bytes --]

--- src/emacs.c.orig	2008-01-10 21:16:14.000000000 +0900
+++ src/emacs.c	2008-04-26 00:44:31.000000000 +0900
@@ -1588,6 +1588,7 @@
       syms_of_vmsproc ();
 #endif /* VMS */
 #ifdef WINDOWSNT
+      syms_of_w32 ();
       syms_of_ntproc ();
 #endif /* WINDOWSNT */
       syms_of_window ();
--- src/fileio.c.orig	2008-03-11 10:56:52.000000000 +0900
+++ src/fileio.c	2008-04-25 22:32:53.000000000 +0900
@@ -231,6 +231,13 @@
 int write_region_inhibit_fsync;
 #endif
 
+/* Nonzero means call move-file-to-trash in Fdelete_file or
+   Fdelete_directory.  */
+int delete_by_moving_to_trash;
+
+/* Lisp functions for move file to trash */
+Lisp_Object Qmove_file_to_trash;
+
 extern Lisp_Object Vuser_login_name;
 
 #ifdef WINDOWSNT
@@ -2669,6 +2676,9 @@
   if (!NILP (handler))
     return call2 (handler, Qdelete_directory, directory);
 
+  if (delete_by_moving_to_trash)
+    return call1 (Qmove_file_to_trash, directory);
+
   encoded_dir = ENCODE_FILE (directory);
 
   dir = SDATA (encoded_dir);
@@ -2702,6 +2712,9 @@
   if (!NILP (handler))
     return call2 (handler, Qdelete_file, filename);
 
+  if (delete_by_moving_to_trash)
+    return call1 (Qmove_file_to_trash, filename);
+
   encoded_file = ENCODE_FILE (filename);
 
   if (0 > unlink (SDATA (encoded_file)))
@@ -6757,6 +6770,13 @@
   write_region_inhibit_fsync = 0;
 #endif
 
+  DEFVAR_BOOL ("delete-by-moving-to-trash", &delete_by_moving_to_trash,
+	       doc: /* Non-nil means redirect to `move-file-to-trash'
+by `delete-file' or `delete-directory'.  */);
+  delete_by_moving_to_trash = 0;
+  Qmove_file_to_trash = intern ("move-file-to-trash");
+  staticpro (&Qmove_file_to_trash);
+
   defsubr (&Sfind_file_name_handler);
   defsubr (&Sfile_name_directory);
   defsubr (&Sfile_name_nondirectory);
--- src/lisp.h.orig	2008-01-10 21:16:15.000000000 +0900
+++ src/lisp.h	2008-04-26 04:07:07.582232000 +0900
@@ -2898,6 +2898,8 @@
 extern void init_fileio_once P_ ((void));
 extern Lisp_Object make_temp_name P_ ((Lisp_Object, int));
 EXFUN (Fmake_symbolic_link, 3);
+extern Lisp_Object Qdelete_directory;
+extern Lisp_Object Qdelete_file;
 
 /* Defined in abbrev.c */
 
--- src/w32.c.orig	2008-02-23 22:49:09.000000000 +0900
+++ src/w32.c	2008-04-26 05:47:03.929566500 +0900
@@ -75,6 +75,11 @@
 #include <windows.h>
 #include <shlobj.h>
 
+#include <shellapi.h>
+#ifndef FOF_NO_CONNECTED_ELEMENTS
+#define FOF_NO_CONNECTED_ELEMENTS 0x2000 /* don't operate on connected elements. */
+#endif /* FOF_NO_CONNECTED_ELEMENTS */
+
 #ifdef HAVE_SOCKETS	/* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
 #undef socket
@@ -96,6 +101,8 @@
 #undef sendto
 #endif
 
+#include "charset.h"
+#include "coding.h"
 #include "w32.h"
 #include "ndir.h"
 #include "w32heap.h"
@@ -104,6 +111,7 @@
 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
   (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
 
+void syms_of_w32 ();
 void globals_of_w32 ();
 
 extern Lisp_Object Vw32_downcase_file_names;
@@ -2256,6 +2264,67 @@
   return _unlink (path);
 }
 
+/* deverted from delete-file in fileio.c */
+DEFUN ("w32-move-file-to-trash", Fw32_move_file_to_trash,
+       Sw32_move_file_to_trash, 1, 1, "fMove file to trash: ",
+       doc: /* Move file (or direcotry) named FILENAME.  */)
+     (filename)
+     Lisp_Object filename;
+{
+  Lisp_Object handler;
+  Lisp_Object encoded_file;
+  Lisp_Object operation;
+
+  operation = Qdelete_file;
+  if (!NILP (Ffile_directory_p (filename))
+      && NILP (Ffile_symlink_p (filename)))
+    {
+      operation = Qdelete_directory;
+      filename = Fdirectory_file_name (filename, Qnil);
+    }
+  filename = Fexpand_file_name (filename, Qnil);
+
+  handler = Ffind_file_name_handler (filename, operation);
+  if (!NILP (handler))
+    return call2 (handler, operation, filename);
+
+  encoded_file = ENCODE_FILE (filename);
+
+  {
+    const char * path;
+    SHFILEOPSTRUCT file_op;
+    /* `pFrom' member of struct SHFILEOPSTRUCT:
+       Each file name must be terminated by a single NULL
+       character. An additional NULL character must be appended to the
+       end of the final name to indicate the end of pFrom. */
+    char tmp_path[MAX_PATH + 1];
+
+    path = map_w32_filename (SDATA (encoded_file), NULL);
+
+    /* On Unix, unlink works without write permission. */
+    _chmod (path, 0666);
+
+    memset (tmp_path, 0, sizeof (tmp_path));
+    strcpy (tmp_path, path);
+
+    memset (&file_op, 0, sizeof (file_op));
+    file_op.hwnd = HWND_DESKTOP;
+    file_op.wFunc = FO_DELETE;
+    file_op.pFrom = tmp_path;
+    file_op.pTo = NULL;
+    file_op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
+      | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
+    file_op.fAnyOperationsAborted = FALSE;
+    file_op.hNameMappings = NULL;
+    file_op.lpszProgressTitle = NULL;
+
+    if (SHFileOperation (&file_op) != 0)
+      report_file_error ("Removing old name", list1 (filename));
+  }
+
+  return Qnil;
+}
+
 static FILETIME utc_base_ft;
 static long double utc_base;
 static int init = 0;
@@ -4140,6 +4209,12 @@
   return FALSE;
 }
 
+void
+syms_of_w32 ()
+{
+  defsubr (&Sw32_move_file_to_trash);
+}
+
 /*
 	globals_of_w32 is used to initialize those global variables that
 	must always be initialized on startup even when the global variable
--- src/w32.h.orig	2008-01-10 21:16:16.000000000 +0900
+++ src/w32.h	2008-04-26 00:43:49.000000000 +0900
@@ -129,6 +129,7 @@
 
 extern void init_ntproc (void);
 extern void term_ntproc (void);
+extern void syms_of_w32 (void);
 extern void globals_of_w32 (void);
 extern void syms_of_w32term (void);
 extern void syms_of_w32fns (void);

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-25 21:10 Toru TSUNEYOSHI
@ 2008-04-26  7:25 ` Eli Zaretskii
  2008-04-30 15:00   ` Toru TSUNEYOSHI
  2008-05-25  0:07   ` Toru TSUNEYOSHI
  2008-05-25  1:24 ` Stefan Monnier
  1 sibling, 2 replies; 24+ messages in thread
From: Eli Zaretskii @ 2008-04-26  7:25 UTC (permalink / raw)
  To: Toru TSUNEYOSHI; +Cc: emacs-devel

> From: "Toru TSUNEYOSHI" <t_tuneyosi@hotmail.com>
> Date: Sat, 26 Apr 2008 06:10:34 +0900
> 
>     (w32-move-file-to-trash "~/test/")
>     => ok
> 
> Please use this patch not old one.

Thanks.

Stefan, the w32 bits of this patch are okay, IMO (modulo some minor
renaming and rephrasing of comments).  So it's paperwork time, I
think, unless this is small enough to be accepted without.




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-26  7:25 ` Eli Zaretskii
@ 2008-04-30 15:00   ` Toru TSUNEYOSHI
  2008-05-15 17:36     ` Stefan Monnier
  2008-05-25  0:07   ` Toru TSUNEYOSHI
  1 sibling, 1 reply; 24+ messages in thread
From: Toru TSUNEYOSHI @ 2008-04-30 15:00 UTC (permalink / raw)
  To: emacs-devel; +Cc: Eli Zaretskii

Thanks a lot for your checking sincerely again, Mr. Eli Zaretskii.





^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-30 15:00   ` Toru TSUNEYOSHI
@ 2008-05-15 17:36     ` Stefan Monnier
  0 siblings, 0 replies; 24+ messages in thread
From: Stefan Monnier @ 2008-05-15 17:36 UTC (permalink / raw)
  To: Toru TSUNEYOSHI; +Cc: Eli Zaretskii, emacs-devel

Now that your copyright papers have arrived, could you send us a final
patch to install, together with a corresponding ChangeLog entry?


        Stefan




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-26  7:25 ` Eli Zaretskii
  2008-04-30 15:00   ` Toru TSUNEYOSHI
@ 2008-05-25  0:07   ` Toru TSUNEYOSHI
  1 sibling, 0 replies; 24+ messages in thread
From: Toru TSUNEYOSHI @ 2008-05-25  0:07 UTC (permalink / raw)
  To: emacs-devel; +Cc: Eli Zaretskii

I have already finished the paperwork, and received the paper (pdf
format) from fsf.org. Is there something else I have to do after this
procedure, please tell me.

----- Original Message ----- 
From: "Eli Zaretskii" <eliz@gnu.org>
To: "Toru TSUNEYOSHI" <t_tuneyosi@hotmail.com>
Cc: <emacs-devel@gnu.org>
Sent: Saturday, April 26, 2008 4:25 PM
Subject: Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series


> > From: "Toru TSUNEYOSHI" <t_tuneyosi@hotmail.com>
> > Date: Sat, 26 Apr 2008 06:10:34 +0900
> > 
> >     (w32-move-file-to-trash "~/test/")
> >     => ok
> > 
> > Please use this patch not old one.
> 
> Thanks.
> 
> Stefan, the w32 bits of this patch are okay, IMO (modulo some minor
> renaming and rephrasing of comments).  So it's paperwork time, I
> think, unless this is small enough to be accepted without.
>




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-04-25 21:10 Toru TSUNEYOSHI
  2008-04-26  7:25 ` Eli Zaretskii
@ 2008-05-25  1:24 ` Stefan Monnier
  2008-05-25  9:59   ` Jason Rumney
  1 sibling, 1 reply; 24+ messages in thread
From: Stefan Monnier @ 2008-05-25  1:24 UTC (permalink / raw)
  To: emacs-devel

Can someone take care of installing this, please?


        Stefan


>>>>> "Toru" == Toru TSUNEYOSHI <t_tuneyosi@hotmail.com> writes:

> A bug was function w32-move-file-to-trash in w32.c

> example: ("~/test" is directory)

>     (w32-move-file-to-trash "~/test")
>     => ok
>     (w32-move-file-to-trash "~/test/")
>     => error


> So I fixed it.

>     (w32-move-file-to-trash "~/test/")
>     => ok

> Please use this patch not old one.

> ----- Original Message ----- 
> From: "Toru TSUNEYOSHI" <t_tuneyosi@hotmail.com>
> To: <emacs-devel@gnu.org>
> Cc: "Stefan Monnier" <monnier@iro.umontreal.ca>
> Sent: Saturday, April 26, 2008 5:18 AM
> Subject: Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series


>> Now I made new patch for function move-file-to-trash (maybe as you
>> wrote).
>> 
>> step to enable move-file-to-trash:
>> 
>> cd src
>> patch -i patch__enable_delete_to_trash.diff
>> make all install
>> 
>> Run emacs
>> (load-file "move-file-to-trash.el")
>> (setq delete-by-moving-to-trash t)
>> 
>> I think it is useful. And I wish that someone else improve the code.

> ;; moved to C source code
> ;;
> ;;	(defvar delete-by-moving-to-trash nil
> ;;	  "Non nil means redirect to `move-file-to-trash'
> ;;	by `delete-file' or `delete-directory'")

> (or (functionp 'orig-backup-extract-version)
>     (fset 'orig-backup-extract-version (symbol-function 'backup-extract-version)))
> ;; Note: The following function can deal with directory properly.
> (defun backup-extract-version (fn)
>   "Given the name of a numeric backup file, return the backup number.
> Uses the free variable `backup-extract-version-start', whose value should be
> the index in the name where the version number begins."
>   (if (and (string-match "[0-9]+~/?$" fn backup-extract-version-start)
> 	   (= (match-beginning 0) backup-extract-version-start))
>       (string-to-int (substring fn backup-extract-version-start -1))
>       0))

> (defvar trash-directory "~/.trash"
>   "Trash directory to move file (or directory) by `move-file-to-trash',
> when system-specific move-file-to-trash doesn't exist.
> If set \".trash\", always move to the directory under default-directory.
> See also `delete-by-moving-to-trash'.")

> (defun move-file-to-trash (filename)
>   "Move file (or directory) named FILENAME.
> Usually this function is called by `delete-file' or `delete-directory',
> so must return nil if succeed."
>   (interactive "fMove file to trash: ")
>   (cond
>    ((eq system-type 'windows-nt)
>     (w32-move-file-to-trash filename))
>    (t
>     (let* ((trash-dir	(expand-file-name trash-directory))
> 	   (fn		(directory-file-name (expand-file-name filename)))
> 	   (fn-nondir	(file-name-nondirectory fn))
> 	   (new-fn	(expand-file-name fn-nondir trash-dir)))
>       (or (file-directory-p trash-dir)
> 	  (make-directory trash-dir t))
>       (when (file-exists-p new-fn)
> 	;; change unique new-fn.
> 	;; example: "~/.trash/abc.txt" -> "~/.trash/abc.txt.~1~"
> 	(let ((version-control t))
> 	  (setq new-fn (car (find-backup-file-name new-fn)))))
>       ;; stop processing if fn is same or parent directory of trash-dir.
>       (and (string-match fn trash-dir)
> 	   (error (message "filename `%s' is same or parent directory of trash-directory."
> 			   filename)))
>       (rename-file fn new-fn)))))

> --- src/emacs.c.orig	2008-01-10 21:16:14.000000000 +0900
> +++ src/emacs.c	2008-04-26 00:44:31.000000000 +0900
> @@ -1588,6 +1588,7 @@
>        syms_of_vmsproc ();
>  #endif /* VMS */
>  #ifdef WINDOWSNT
> +      syms_of_w32 ();
>        syms_of_ntproc ();
>  #endif /* WINDOWSNT */
>        syms_of_window ();
> --- src/fileio.c.orig	2008-03-11 10:56:52.000000000 +0900
> +++ src/fileio.c	2008-04-25 22:32:53.000000000 +0900
> @@ -231,6 +231,13 @@
>  int write_region_inhibit_fsync;
>  #endif
 
> +/* Nonzero means call move-file-to-trash in Fdelete_file or
> +   Fdelete_directory.  */
> +int delete_by_moving_to_trash;
> +
> +/* Lisp functions for move file to trash */
> +Lisp_Object Qmove_file_to_trash;
> +
>  extern Lisp_Object Vuser_login_name;
 
>  #ifdef WINDOWSNT
> @@ -2669,6 +2676,9 @@
>    if (!NILP (handler))
>      return call2 (handler, Qdelete_directory, directory);
 
> +  if (delete_by_moving_to_trash)
> +    return call1 (Qmove_file_to_trash, directory);
> +
>    encoded_dir = ENCODE_FILE (directory);
 
>    dir = SDATA (encoded_dir);
> @@ -2702,6 +2712,9 @@
>    if (!NILP (handler))
>      return call2 (handler, Qdelete_file, filename);
 
> +  if (delete_by_moving_to_trash)
> +    return call1 (Qmove_file_to_trash, filename);
> +
>    encoded_file = ENCODE_FILE (filename);
 
>    if (0 > unlink (SDATA (encoded_file)))
> @@ -6757,6 +6770,13 @@
>    write_region_inhibit_fsync = 0;
>  #endif
 
> +  DEFVAR_BOOL ("delete-by-moving-to-trash", &delete_by_moving_to_trash,
> +	       doc: /* Non-nil means redirect to `move-file-to-trash'
> +by `delete-file' or `delete-directory'.  */);
> +  delete_by_moving_to_trash = 0;
> +  Qmove_file_to_trash = intern ("move-file-to-trash");
> +  staticpro (&Qmove_file_to_trash);
> +
>    defsubr (&Sfind_file_name_handler);
>    defsubr (&Sfile_name_directory);
>    defsubr (&Sfile_name_nondirectory);
> --- src/lisp.h.orig	2008-01-10 21:16:15.000000000 +0900
> +++ src/lisp.h	2008-04-26 04:07:07.582232000 +0900
> @@ -2898,6 +2898,8 @@
>  extern void init_fileio_once P_ ((void));
>  extern Lisp_Object make_temp_name P_ ((Lisp_Object, int));
>  EXFUN (Fmake_symbolic_link, 3);
> +extern Lisp_Object Qdelete_directory;
> +extern Lisp_Object Qdelete_file;
 
>  /* Defined in abbrev.c */
 
> --- src/w32.c.orig	2008-02-23 22:49:09.000000000 +0900
> +++ src/w32.c	2008-04-26 05:47:03.929566500 +0900
> @@ -75,6 +75,11 @@
>  #include <windows.h>
>  #include <shlobj.h>
 
> +#include <shellapi.h>
> +#ifndef FOF_NO_CONNECTED_ELEMENTS
> +#define FOF_NO_CONNECTED_ELEMENTS 0x2000 /* don't operate on connected elements. */
> +#endif /* FOF_NO_CONNECTED_ELEMENTS */
> +
>  #ifdef HAVE_SOCKETS	/* TCP connection support, if kernel can do it */
>  #include <sys/socket.h>
>  #undef socket
> @@ -96,6 +101,8 @@
>  #undef sendto
>  #endif
 
> +#include "charset.h"
> +#include "coding.h"
>  #include "w32.h"
>  #include "ndir.h"
>  #include "w32heap.h"
> @@ -104,6 +111,7 @@
>  typedef HRESULT (WINAPI * ShGetFolderPath_fn)
>    (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
 
> +void syms_of_w32 ();
>  void globals_of_w32 ();
 
>  extern Lisp_Object Vw32_downcase_file_names;
> @@ -2256,6 +2264,67 @@
>    return _unlink (path);
>  }
 
> +/* deverted from delete-file in fileio.c */
> +DEFUN ("w32-move-file-to-trash", Fw32_move_file_to_trash,
> +       Sw32_move_file_to_trash, 1, 1, "fMove file to trash: ",
> +       doc: /* Move file (or direcotry) named FILENAME.  */)
> +     (filename)
> +     Lisp_Object filename;
> +{
> +  Lisp_Object handler;
> +  Lisp_Object encoded_file;
> +  Lisp_Object operation;
> +
> +  operation = Qdelete_file;
> +  if (!NILP (Ffile_directory_p (filename))
> +      && NILP (Ffile_symlink_p (filename)))
> +    {
> +      operation = Qdelete_directory;
> +      filename = Fdirectory_file_name (filename, Qnil);
> +    }
> +  filename = Fexpand_file_name (filename, Qnil);
> +
> +  handler = Ffind_file_name_handler (filename, operation);
> +  if (!NILP (handler))
> +    return call2 (handler, operation, filename);
> +
> +  encoded_file = ENCODE_FILE (filename);
> +
> +  {
> +    const char * path;
> +    SHFILEOPSTRUCT file_op;
> +    /* `pFrom' member of struct SHFILEOPSTRUCT:
> +       Each file name must be terminated by a single NULL
> +       character. An additional NULL character must be appended to the
> +       end of the final name to indicate the end of pFrom. */
> +    char tmp_path[MAX_PATH + 1];
> +
> +    path = map_w32_filename (SDATA (encoded_file), NULL);
> +
> +    /* On Unix, unlink works without write permission. */
> +    _chmod (path, 0666);
> +
> +    memset (tmp_path, 0, sizeof (tmp_path));
> +    strcpy (tmp_path, path);
> +
> +    memset (&file_op, 0, sizeof (file_op));
> +    file_op.hwnd = HWND_DESKTOP;
> +    file_op.wFunc = FO_DELETE;
> +    file_op.pFrom = tmp_path;
> +    file_op.pTo = NULL;
> +    file_op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
> +      | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
> +    file_op.fAnyOperationsAborted = FALSE;
> +    file_op.hNameMappings = NULL;
> +    file_op.lpszProgressTitle = NULL;
> +
> +    if (SHFileOperation (&file_op) != 0)
> +      report_file_error ("Removing old name", list1 (filename));
> +  }
> +
> +  return Qnil;
> +}
> +
>  static FILETIME utc_base_ft;
>  static long double utc_base;
>  static int init = 0;
> @@ -4140,6 +4209,12 @@
>    return FALSE;
>  }
 
> +void
> +syms_of_w32 ()
> +{
> +  defsubr (&Sw32_move_file_to_trash);
> +}
> +
>  /*
>  	globals_of_w32 is used to initialize those global variables that
>  	must always be initialized on startup even when the global variable
> --- src/w32.h.orig	2008-01-10 21:16:16.000000000 +0900
> +++ src/w32.h	2008-04-26 00:43:49.000000000 +0900
> @@ -129,6 +129,7 @@
 
>  extern void init_ntproc (void);
>  extern void term_ntproc (void);
> +extern void syms_of_w32 (void);
>  extern void globals_of_w32 (void);
>  extern void syms_of_w32term (void);
>  extern void syms_of_w32fns (void);




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-05-25  1:24 ` Stefan Monnier
@ 2008-05-25  9:59   ` Jason Rumney
  2008-05-25 11:22     ` Stefan Monnier
  0 siblings, 1 reply; 24+ messages in thread
From: Jason Rumney @ 2008-05-25  9:59 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier wrote:

>> (defvar trash-directory "~/.trash"
>>     

Is this deliberate, to not interfere with the standard "~/.Trash" directory?

>>   (cond
>>    ((eq system-type 'windows-nt)
>>     (w32-move-file-to-trash filename))
>>     

This might be better as
   ((fboundp 'system-move-file-to-trash)
     (system-move-file-to-trash filename))

Then adding a proper implementation for the freedesktop.org standard 
will be as simple as defining such a function in the GTK (for example) 
code. Likewise for Mac OSX.





^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-05-25  9:59   ` Jason Rumney
@ 2008-05-25 11:22     ` Stefan Monnier
  0 siblings, 0 replies; 24+ messages in thread
From: Stefan Monnier @ 2008-05-25 11:22 UTC (permalink / raw)
  To: Jason Rumney; +Cc: emacs-devel

>>> (defvar trash-directory "~/.trash"
> Is this deliberate, to not interfere with the standard "~/.Trash" directory?

I don't think so.  So, feel free to replace it with ~/.Trash.

>>> (cond
>>> ((eq system-type 'windows-nt)
>>> (w32-move-file-to-trash filename))

> This might be better as
>   ((fboundp 'system-move-file-to-trash)
>     (system-move-file-to-trash filename))

> Then adding a proper implementation for the freedesktop.org standard will be
> as simple as defining such a function in the GTK (for example)
> code. Likewise for Mac OSX.

Sounds fine,


        Stefan




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
@ 2008-05-27 17:11 Toru TSUNEYOSHI
  2008-05-27 18:39 ` Stefan Monnier
  0 siblings, 1 reply; 24+ messages in thread
From: Toru TSUNEYOSHI @ 2008-05-27 17:11 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 373 bytes --]

Thanks for your helping, Jason and Stefan.
I fixed a patch according to it.
(I read archives on http://lists.gnu.org/archive/html/emacs-devel/.)

(I write again.)
step to enable move-file-to-trash:

    cd src
    patch -i patch__enable_delete_to_trash.diff
    make all install

    Run emacs
    (load-file "move-file-to-trash.el")
    (setq delete-by-moving-to-trash t)

[-- Attachment #2: move-file-to-trash.el --]
[-- Type: application/octet-stream, Size: 2154 bytes --]

;; moved to C source code
;;
;;	(defvar delete-by-moving-to-trash nil
;;	  "Non nil means redirect to `move-file-to-trash'
;;	by `delete-file' or `delete-directory'")

(or (functionp 'orig-backup-extract-version)
    (fset 'orig-backup-extract-version (symbol-function 'backup-extract-version)))
;; Note: The following function can deal with directory properly.
(defun backup-extract-version (fn)
  "Given the name of a numeric backup file, return the backup number.
Uses the free variable `backup-extract-version-start', whose value should be
the index in the name where the version number begins."
  (if (and (string-match "[0-9]+~/?$" fn backup-extract-version-start)
	   (= (match-beginning 0) backup-extract-version-start))
      (string-to-int (substring fn backup-extract-version-start -1))
      0))

(defvar trash-directory "~/.Trash"
  "Trash directory to move file (or directory) by `move-file-to-trash',
when system-specific move-file-to-trash doesn't exist.
If set \".Trash\", always move to the directory under default-directory.
See also `delete-by-moving-to-trash'.")

(defun move-file-to-trash (filename)
  "Move file (or directory) named FILENAME.
Usually this function is called by `delete-file' or `delete-directory',
so must return nil if succeed."
  (interactive "fMove file to trash: ")
  (cond
   ((fboundp 'system-move-file-to-trash)
    (system-move-file-to-trash filename))
   (t
    (let* ((trash-dir	(expand-file-name trash-directory))
	   (fn		(directory-file-name (expand-file-name filename)))
	   (fn-nondir	(file-name-nondirectory fn))
	   (new-fn	(expand-file-name fn-nondir trash-dir)))
      (or (file-directory-p trash-dir)
	  (make-directory trash-dir t))
      (and (file-exists-p new-fn)
	   ;; make new-fn unique.
	   ;; example: "~/.Trash/abc.txt" -> "~/.Trash/abc.txt.~1~"
	   (let ((version-control t))
	     (setq new-fn (car (find-backup-file-name new-fn)))))
      ;; stop processing if fn is same or parent directory of trash-dir.
      (and (string-match fn trash-dir)
	   (error (message "filename `%s' is same or parent directory of trash-directory."
			   filename)))
      (rename-file fn new-fn)))))

[-- Attachment #3: patch__enable_delete_to_trash.diff --]
[-- Type: application/octet-stream, Size: 5681 bytes --]

--- src/emacs.c.orig	2008-01-10 21:16:14.000000000 +0900
+++ src/emacs.c	2008-05-26 23:33:50.355468800 +0900
@@ -1588,6 +1588,7 @@
       syms_of_vmsproc ();
 #endif /* VMS */
 #ifdef WINDOWSNT
+      syms_of_w32 ();
       syms_of_ntproc ();
 #endif /* WINDOWSNT */
       syms_of_window ();
--- src/fileio.c.orig	2008-03-11 10:56:52.000000000 +0900
+++ src/fileio.c	2008-05-26 23:33:50.385512000 +0900
@@ -231,6 +231,13 @@
 int write_region_inhibit_fsync;
 #endif
 
+/* Nonzero means call move-file-to-trash in Fdelete_file or
+   Fdelete_directory.  */
+int delete_by_moving_to_trash;
+
+/* Lisp functions for move file to trash */
+Lisp_Object Qmove_file_to_trash;
+
 extern Lisp_Object Vuser_login_name;
 
 #ifdef WINDOWSNT
@@ -2669,6 +2676,9 @@
   if (!NILP (handler))
     return call2 (handler, Qdelete_directory, directory);
 
+  if (delete_by_moving_to_trash)
+    return call1 (Qmove_file_to_trash, directory);
+
   encoded_dir = ENCODE_FILE (directory);
 
   dir = SDATA (encoded_dir);
@@ -2702,6 +2712,9 @@
   if (!NILP (handler))
     return call2 (handler, Qdelete_file, filename);
 
+  if (delete_by_moving_to_trash)
+    return call1 (Qmove_file_to_trash, filename);
+
   encoded_file = ENCODE_FILE (filename);
 
   if (0 > unlink (SDATA (encoded_file)))
@@ -6757,6 +6770,13 @@
   write_region_inhibit_fsync = 0;
 #endif
 
+  DEFVAR_BOOL ("delete-by-moving-to-trash", &delete_by_moving_to_trash,
+	       doc: /* Non-nil means redirect to `move-file-to-trash'
+by `delete-file' or `delete-directory'.  */);
+  delete_by_moving_to_trash = 0;
+  Qmove_file_to_trash = intern ("move-file-to-trash");
+  staticpro (&Qmove_file_to_trash);
+
   defsubr (&Sfind_file_name_handler);
   defsubr (&Sfile_name_directory);
   defsubr (&Sfile_name_nondirectory);
--- src/lisp.h.orig	2008-01-10 21:16:15.000000000 +0900
+++ src/lisp.h	2008-05-26 23:33:50.415555200 +0900
@@ -2898,6 +2898,8 @@
 extern void init_fileio_once P_ ((void));
 extern Lisp_Object make_temp_name P_ ((Lisp_Object, int));
 EXFUN (Fmake_symbolic_link, 3);
+extern Lisp_Object Qdelete_directory;
+extern Lisp_Object Qdelete_file;
 
 /* Defined in abbrev.c */
 
--- src/w32.c.orig	2008-02-23 22:49:09.000000000 +0900
+++ src/w32.c	2008-05-28 01:14:30.334352800 +0900
@@ -75,6 +75,11 @@
 #include <windows.h>
 #include <shlobj.h>
 
+#include <shellapi.h>
+#ifndef FOF_NO_CONNECTED_ELEMENTS
+#define FOF_NO_CONNECTED_ELEMENTS 0x2000
+#endif /* FOF_NO_CONNECTED_ELEMENTS */
+
 #ifdef HAVE_SOCKETS	/* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
 #undef socket
@@ -96,6 +101,8 @@
 #undef sendto
 #endif
 
+#include "charset.h"
+#include "coding.h"
 #include "w32.h"
 #include "ndir.h"
 #include "w32heap.h"
@@ -104,6 +111,7 @@
 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
   (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
 
+void syms_of_w32 ();
 void globals_of_w32 ();
 
 extern Lisp_Object Vw32_downcase_file_names;
@@ -2256,6 +2264,65 @@
   return _unlink (path);
 }
 
+/* deverted from delete-file in fileio.c */
+DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash,
+       Ssystem_move_file_to_trash, 1, 1, "fMove file to trash: ",
+       doc: /* Move file (or direcotry) named FILENAME.  */)
+     (filename)
+     Lisp_Object filename;
+{
+  Lisp_Object handler;
+  Lisp_Object encoded_file;
+  Lisp_Object operation;
+
+  operation = Qdelete_file;
+  if (!NILP (Ffile_directory_p (filename))
+      && NILP (Ffile_symlink_p (filename)))
+    {
+      operation = Qdelete_directory;
+      filename = Fdirectory_file_name (filename, Qnil);
+    }
+  filename = Fexpand_file_name (filename, Qnil);
+
+  handler = Ffind_file_name_handler (filename, operation);
+  if (!NILP (handler))
+    return call2 (handler, operation, filename);
+
+  encoded_file = ENCODE_FILE (filename);
+
+  {
+    const char * path;
+    SHFILEOPSTRUCT file_op;
+    /* +1 means space for NULL character representing the end of the
+       final name to indicate the pFrom member of struct SHFILEOPSTRUCT */
+    char tmp_path[MAX_PATH + 1];
+
+    path = map_w32_filename (SDATA (encoded_file), NULL);
+
+    /* On Unix, unlink works without write permission. */
+    _chmod (path, 0666);
+
+    memset (tmp_path, 0, sizeof (tmp_path));
+    strcpy (tmp_path, path);
+
+    memset (&file_op, 0, sizeof (file_op));
+    file_op.hwnd = HWND_DESKTOP;
+    file_op.wFunc = FO_DELETE;
+    file_op.pFrom = tmp_path;
+    file_op.pTo = NULL;
+    file_op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
+      | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
+    file_op.fAnyOperationsAborted = FALSE;
+    file_op.hNameMappings = NULL;
+    file_op.lpszProgressTitle = NULL;
+
+    if (SHFileOperation (&file_op) != 0)
+      report_file_error ("Removing old name", list1 (filename));
+  }
+
+  return Qnil;
+}
+
 static FILETIME utc_base_ft;
 static long double utc_base;
 static int init = 0;
@@ -4140,6 +4207,12 @@
   return FALSE;
 }
 
+void
+syms_of_w32 ()
+{
+  defsubr (&Ssystem_move_file_to_trash);
+}
+
 /*
 	globals_of_w32 is used to initialize those global variables that
 	must always be initialized on startup even when the global variable
--- src/w32.h.orig	2008-01-10 21:16:16.000000000 +0900
+++ src/w32.h	2008-05-26 23:33:50.485656000 +0900
@@ -129,6 +129,7 @@
 
 extern void init_ntproc (void);
 extern void term_ntproc (void);
+extern void syms_of_w32 (void);
 extern void globals_of_w32 (void);
 extern void syms_of_w32term (void);
 extern void syms_of_w32fns (void);

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: patch about moving file (or directory) to the Recycle Bin on Windows NT series
  2008-05-27 17:11 Toru TSUNEYOSHI
@ 2008-05-27 18:39 ` Stefan Monnier
  0 siblings, 0 replies; 24+ messages in thread
From: Stefan Monnier @ 2008-05-27 18:39 UTC (permalink / raw)
  To: Toru TSUNEYOSHI; +Cc: emacs-devel

Can someone please install it?


        Stefan


>>>>> "Toru" == Toru TSUNEYOSHI <t_tuneyosi@hotmail.com> writes:

> Thanks for your helping, Jason and Stefan.
> I fixed a patch according to it.
> (I read archives on http://lists.gnu.org/archive/html/emacs-devel/.)

> (I write again.)
> step to enable move-file-to-trash:

>     cd src
>     patch -i patch__enable_delete_to_trash.diff
>     make all install

>     Run emacs
>     (load-file "move-file-to-trash.el")
>     (setq delete-by-moving-to-trash t)






^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2008-05-27 18:39 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-21 21:32 patch about moving file (or directory) to the Recycle Bin on Windows NT series Toru TSUNEYOSHI
2008-04-22  9:02 ` Toru TSUNEYOSHI
2008-04-22 15:47   ` Stefan Monnier
2008-04-22 17:04     ` Eli Zaretskii
2008-04-22 18:24       ` Eli Zaretskii
2008-04-22 18:19 ` Eli Zaretskii
2008-04-22 20:58   ` Jason Rumney
2008-04-23  1:15     ` Stefan Monnier
2008-04-23  1:14   ` Stefan Monnier
2008-04-23  4:55     ` Eli Zaretskii
2008-04-23 16:45   ` Toru TSUNEYOSHI
2008-04-23 15:35 ` Stefan Monnier
2008-04-25 20:18   ` Toru TSUNEYOSHI
  -- strict thread matches above, loose matches on Subject: below --
2008-05-27 17:11 Toru TSUNEYOSHI
2008-05-27 18:39 ` Stefan Monnier
2008-04-25 21:10 Toru TSUNEYOSHI
2008-04-26  7:25 ` Eli Zaretskii
2008-04-30 15:00   ` Toru TSUNEYOSHI
2008-05-15 17:36     ` Stefan Monnier
2008-05-25  0:07   ` Toru TSUNEYOSHI
2008-05-25  1:24 ` Stefan Monnier
2008-05-25  9:59   ` Jason Rumney
2008-05-25 11:22     ` Stefan Monnier
     [not found] <BAY121-DAV73ED6DDCDAB11014BA9E6E2E10@phx.gbl>
     [not found] ` <480CC2D7.3030302@gmail.com>
2008-04-21 17:07   ` Toru TSUNEYOSHI

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).