revert between 56095 -> 55830 in arch
[AROS.git] / workbench / c / Delete.c
blobb51fd4c10390a0f733d8481704da9f71588703e7
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Delete CLI Command.
6 */
8 /*****************************************************************************
10 NAME
12 Delete
14 SYNOPSIS
16 Delete { (name | pattern) } [ALL] [QUIET] [FORCE]
18 LOCATION
22 FUNCTION
24 Deletes files and directories. You may delete several files and directories
25 by listing them separately or by using wildcards. To abort a multiple
26 delete, press CTRL-C. Delete will notify the user of which files it
27 weren't able to delete.
28 Delete cannot delete directories which are not empty unless the
29 ALL option is used. To suppress file and directory names from being
30 printed while deleted use the QUIET option. If the 'd' protection bit
31 is cleared for a file or directory, it may not be deleted unless the
32 FORCE option is used.
34 INPUTS
36 FILE/M/A -- files or directories to delete (may contain patterns)
37 ALL/S -- recursively delete dirctories
38 QUIET/S -- don't print which files/directories were deleted
39 FORCE/S -- delete files/directories even if they are protected from
40 deletion
42 RESULT
44 NOTES
46 EXAMPLE
48 Delete RAM:T/#? ALL FORCE
50 Deletes all directories and files recursively in the directory RAM:T
51 even if they are protected from deletion.
54 BUGS
56 SEE ALSO
58 INTERNALS
60 Shows a good usage of the pattern matching capabilities.
62 ******************************************************************************/
64 #include <proto/dos.h>
65 #include <proto/exec.h>
67 #include <dos/dos.h>
68 #include <dos/dosasl.h>
69 #include <exec/memory.h>
71 #include <string.h>
74 #define ARG_TEMPLATE "FILE/M/A,ALL/S,QUIET/S,FORCE/S,FOLLOWLINKS/S"
76 enum
78 ARG_FILE = 0,
79 ARG_ALL,
80 ARG_QUIET,
81 ARG_FORCE,
82 ARG_FOLLOWLINKS,
83 NOOFARGS
87 /* Maximum file path length */
88 #define MAX_PATH_LEN 2048
90 const TEXT version[] = "$VER: Delete 41.3 (27.7.2016)\n";
91 static char cmdname[] = "Delete";
94 int doDelete(struct AnchorPath *ap, STRPTR *files, BOOL all, BOOL quiet,
95 BOOL force, BOOL forcelinks);
97 int __nocommandline;
99 int main(void)
101 struct RDArgs *rda;
102 struct AnchorPath *ap;
103 IPTR args[NOOFARGS] = { (IPTR) NULL, FALSE, FALSE, FALSE, FALSE };
104 int retval = RETURN_OK;
106 ap = AllocVec(sizeof(struct AnchorPath) + MAX_PATH_LEN,
107 MEMF_ANY | MEMF_CLEAR);
109 if (ap != NULL)
111 ap->ap_Strlen = MAX_PATH_LEN;
113 rda = ReadArgs(ARG_TEMPLATE, args, NULL);
115 if (rda != NULL)
117 /* Convert arguments into (less complex) variables */
118 STRPTR *files = (STRPTR *)args[ARG_FILE];
119 BOOL all = (BOOL)args[ARG_ALL];
120 BOOL quiet = (BOOL)args[ARG_QUIET];
121 BOOL force = (BOOL)args[ARG_FORCE];
122 BOOL followlinks = (BOOL)args[ARG_FOLLOWLINKS];
124 retval = doDelete(ap, files, all, quiet, force, followlinks);
126 FreeArgs(rda);
128 else
130 PrintFault(IoErr(), cmdname);
131 retval = RETURN_FAIL;
134 else
136 retval = RETURN_FAIL;
139 FreeVec(ap);
141 return retval;
142 } /* main */
144 static inline BOOL isDirectory(struct AnchorPath *ap, BOOL followflag)
146 BOOL isdir;
148 if (ap->ap_Info.fib_DirEntryType == ST_SOFTLINK)
150 /* Softlink to dir/file - Default don't enter it, unless
151 flag is set and the destination is really softlink.
153 We have all lost some files due to braindead behaviour
154 of the original delete regarding softlinks. - Piru
156 isdir = FALSE;
158 if (followflag)
160 /* Okay flag set, figure out if this is a softlink to directory
162 BPTR lock;
164 lock = Lock(ap->ap_Buf, ACCESS_READ);
165 if (lock)
167 struct FileInfoBlock *fib;
169 fib = AllocDosObject(DOS_FIB, NULL);
170 if (fib)
172 if (Examine(lock, fib))
174 /* Just extra sanity check so it can't be softlink
175 anymore (weird, fucked up, fs?).
177 isdir = (fib->fib_DirEntryType >= 0 &&
178 fib->fib_DirEntryType != ST_SOFTLINK);
180 FreeDosObject(DOS_FIB, fib);
182 UnLock(lock);
186 else if (ap->ap_Info.fib_DirEntryType == ST_LINKDIR)
188 /* Hardlink to directory - Only follow it if flag set.
190 It is debatable whether hardlinks should be followed by
191 default. IMHO not. - Piru
193 isdir = followflag;
195 else
197 isdir = ap->ap_Info.fib_DirEntryType >= 0;
199 return isdir;
202 #define isDeletable(fib) (!((fib)->fib_Protection & FIBF_DELETE))
204 int doDelete(struct AnchorPath *ap, STRPTR *files, BOOL all, BOOL quiet,
205 BOOL force, BOOL forcelinks)
207 LONG match = 0;
208 int i;
209 char name[MAX_PATH_LEN];
210 BOOL deleteit = FALSE;
211 BOOL deletedfile = FALSE;
212 BOOL firstmatch = TRUE;
214 if (!files)
216 return RETURN_OK;
219 for (i = 0; files[i] != NULL; i++)
221 /* Index for last character in the current file name (pattern name) */
222 int lastIndex = strlen(files[i]) - 1;
224 if (files[i][lastIndex] == ':')
226 struct DosList *dl = LockDosList(LDF_ALL | LDF_READ);
228 if (FindDosEntry(dl, (CONST_STRPTR)files[i], LDF_ALL | LDF_READ))
230 MatchEnd(ap);
231 UnLockDosList(LDF_ALL | LDF_READ);
233 Printf("%s is a device and cannot be deleted\n", files[i]);
235 return RETURN_FAIL;
237 UnLockDosList(LDF_ALL | LDF_READ);
240 for (match = MatchFirst(files[i], ap); match == 0;
241 match = MatchNext(ap))
243 firstmatch = FALSE;
245 if (CheckSignal(SIGBREAKF_CTRL_C))
247 MatchEnd(ap);
248 PrintFault(ERROR_BREAK,"");
250 return RETURN_ERROR;
253 if (deleteit)
255 deletedfile = FALSE;
256 /* Try to delete the file or directory */
257 if (!DeleteFile(name))
259 LONG ioerr = IoErr();
260 Printf("%s Not Deleted", (IPTR)name);
261 PrintFault(ioerr, "");
263 else
265 deletedfile = TRUE;
266 if (!quiet)
268 Printf("%s Deleted\n", (IPTR)name);
271 deleteit = FALSE;
274 /* If this is a directory, we enter it regardless if the ALL
275 switch is set. */
276 if (isDirectory(ap, forcelinks))
278 /* This is a directory. It's important to check if we just left
279 the directory or is about to enter it. This is because we
280 cannot delete a directory until we have deleted all the
281 files in it. */
282 if (ap->ap_Flags & APF_DIDDIR)
284 /* If we get here, we are in ALL mode and have deleted
285 all the files inside the dir (if none were protected
286 and such). */
288 ap->ap_Flags &= ~APF_DIDDIR;
290 /* Now go on and delete the directory */
292 else
294 /* We stumbled upon a directory */
296 if(all)
298 ap->ap_Flags |= APF_DODIR;
300 /* We don't want to delete a directory before deleting
301 possible files inside it. Thus, match next file */
302 continue;
305 /* If all is not set, DeleteFile() will return an error
306 in case the directory was not empty. */
309 /* Mark the entry for deletion */
310 deleteit = TRUE;
312 /* Check permissions */
313 if (!isDeletable(&ap->ap_Info))
315 /* Consider delete protected file/dir 'deleted' */
316 deletedfile = TRUE;
318 if (force)
319 SetProtection(ap->ap_Buf, 0);
320 else
322 Printf("%s Not Deleted", (IPTR)ap->ap_Buf);
323 PrintFault(ERROR_DELETE_PROTECTED, "");
324 deleteit = FALSE;
327 strcpy(name, ap->ap_Buf);
329 MatchEnd(ap);
330 if (deleteit)
332 deletedfile = FALSE;
333 /* Try to delete the file or directory */
334 if (!DeleteFile(name))
336 LONG ioerr = IoErr();
337 Printf("%s Not Deleted", (IPTR)name);
338 PrintFault(ioerr, "");
339 if (ioerr == ERROR_DISK_WRITE_PROTECTED)
341 return RETURN_FAIL;
344 else
346 deletedfile = TRUE;
347 if (!quiet)
349 Printf("%s Deleted\n", (IPTR)name);
352 deleteit = FALSE;
356 if (firstmatch && match &&
357 match != ERROR_OBJECT_NOT_FOUND &&
358 match != ERROR_NO_MORE_ENTRIES)
360 PrintFault(match, NULL);
361 return RETURN_WARN;
364 if (!deletedfile)
366 PutStr("No file to delete\n");
367 return RETURN_WARN;
369 return RETURN_OK;