define __KERNEL_STRICT_NAMES to avoid inclusion of kernel types on systems that carry...
[cake.git] / workbench / c / Delete.c
blobe2fa3729b55663f263b1a5f8fb55cb3451b62ead
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
20 Sys:c
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 <stdio.h>
72 #include <string.h>
75 #define ARG_TEMPLATE "FILE/M/A,ALL/S,QUIET/S,FORCE/S,FOLLOWLINKS/S"
77 enum
79 ARG_FILE = 0,
80 ARG_ALL,
81 ARG_QUIET,
82 ARG_FORCE,
83 ARG_FOLLOWLINKS,
84 NOOFARGS
88 /* Maximum file path length */
89 #define MAX_PATH_LEN 2048
91 const TEXT version[] = "$VER: Delete 41.2 (6.1.2000)\n";
92 static char cmdname[] = "Delete";
95 int doDelete(struct AnchorPath *ap, STRPTR *files, BOOL all, BOOL quiet,
96 BOOL force, BOOL forcelinks);
98 int __nocommandline;
100 int main(void)
102 struct RDArgs *rda;
103 struct AnchorPath *ap;
104 IPTR args[NOOFARGS] = { (IPTR) NULL, FALSE, FALSE, FALSE, FALSE };
105 int retval = RETURN_OK;
107 ap = AllocVec(sizeof(struct AnchorPath) + MAX_PATH_LEN,
108 MEMF_ANY | MEMF_CLEAR);
110 if (ap != NULL)
112 ap->ap_Strlen = MAX_PATH_LEN;
114 rda = ReadArgs(ARG_TEMPLATE, args, NULL);
116 if (rda != NULL)
118 /* Convert arguments into (less complex) variables */
119 STRPTR *files = (STRPTR *)args[ARG_FILE];
120 BOOL all = (BOOL)args[ARG_ALL];
121 BOOL quiet = (BOOL)args[ARG_QUIET];
122 BOOL force = (BOOL)args[ARG_FORCE];
123 BOOL followlinks = (BOOL)args[ARG_FOLLOWLINKS];
125 retval = doDelete(ap, files, all, quiet, force, followlinks);
127 FreeArgs(rda);
129 else
131 PrintFault(IoErr(), cmdname);
132 retval = RETURN_FAIL;
135 else
137 retval = RETURN_FAIL;
140 FreeVec(ap);
142 return retval;
143 } /* main */
145 static inline BOOL isDirectory(struct AnchorPath *ap, BOOL followflag)
147 BOOL isdir;
149 if (ap->ap_Info.fib_DirEntryType == ST_SOFTLINK)
151 /* Softlink to dir/file - Default don't enter it, unless
152 flag is set and the destination is really softlink.
154 We have all lost some files due to braindead behaviour
155 of the original delete regarding softlinks. - Piru
157 isdir = FALSE;
159 if (followflag)
161 /* Okay flag set, figure out if this is a softlink to directory
163 BPTR lock;
165 lock = Lock(ap->ap_Buf, ACCESS_READ);
166 if (lock)
168 struct FileInfoBlock *fib;
170 fib = AllocDosObject(DOS_FIB, NULL);
171 if (fib)
173 if (Examine(lock, fib))
175 /* Just extra sanity check so it can't be softlink
176 anymore (weird, fucked up, fs?).
178 isdir = (fib->fib_DirEntryType >= 0 &&
179 fib->fib_DirEntryType != ST_SOFTLINK);
181 FreeDosObject(DOS_FIB, fib);
183 UnLock(lock);
187 else if (ap->ap_Info.fib_DirEntryType == ST_LINKDIR)
189 /* Hardlink to directory - Only follow it if flag set.
191 It is debatable whether hardlinks should be followed by
192 default. IMHO not. - Piru
194 isdir = followflag;
196 else
198 isdir = ap->ap_Info.fib_DirEntryType >= 0;
200 return isdir;
203 #define isDeletable(fib) (!((fib)->fib_Protection & FIBF_DELETE))
205 int doDelete(struct AnchorPath *ap, STRPTR *files, BOOL all, BOOL quiet,
206 BOOL force, BOOL forcelinks)
208 LONG match;
209 int i;
210 char name[MAX_PATH_LEN];
211 BOOL isfile = TRUE;
212 BOOL deleteit = FALSE;
213 BOOL deletedfile = FALSE;
214 BOOL firstmatch = TRUE;
216 if (!files)
218 return RETURN_OK;
221 for (i = 0; files[i] != NULL; i++)
223 /* Index for last character in the current file name (pattern name) */
224 int lastIndex = strlen(files[i]) - 1;
226 if (files[i][lastIndex] == ':')
228 struct DosList *dl = LockDosList(LDF_ALL | LDF_READ);
230 if (FindDosEntry(dl, (CONST_STRPTR)files[i], LDF_ALL | LDF_READ))
232 MatchEnd(ap);
233 UnLockDosList(LDF_ALL | LDF_READ);
235 Printf("%s is a device and cannot be deleted\n", files[i]);
237 return RETURN_FAIL;
239 UnLockDosList(LDF_ALL | LDF_READ);
242 for (match = MatchFirst(files[i], ap); match == 0;
243 match = MatchNext(ap))
245 firstmatch = FALSE;
247 if (CheckSignal(SIGBREAKF_CTRL_C))
249 MatchEnd(ap);
250 PrintFault(ERROR_BREAK,"");
252 return RETURN_ERROR;
255 if (deleteit)
257 /* Try to delete the file or directory */
258 if (!DeleteFile(name))
260 LONG ioerr = IoErr();
261 Printf("%s Not Deleted", (ULONG)name);
262 PrintFault(ioerr, "");
264 else if (!quiet)
266 Printf("%s Deleted\n", (ULONG)name);
269 deletedfile = TRUE;
270 deleteit = FALSE;
273 /* If this is a directory, we enter it regardless if the ALL
274 switch is set. */
275 if (isDirectory(ap, forcelinks))
277 /* This is a directory. It's important to check if we just left
278 the directory or is about to enter it. This is because we
279 cannot delete a directory until we have deleted all the
280 files in it. */
281 if (ap->ap_Flags & APF_DIDDIR)
283 /* If we get here, we are in ALL mode and have deleted
284 all the files inside the dir (if none were protected
285 and such). */
287 ap->ap_Flags &= ~APF_DIDDIR;
289 /* Now go on and delete the directory */
291 else
293 /* We stumbled upon a directory */
295 if(all)
297 ap->ap_Flags |= APF_DODIR;
299 /* We don't want to delete a directory before deleting
300 possible files inside it. Thus, match next file */
301 continue;
304 /* If all is not set, DeleteFile() will return an error
305 in case the directory was not empty. */
308 /* Mark the entry for deletion */
309 deleteit = TRUE;
311 /* Check permissions */
312 if (!isDeletable(&ap->ap_Info))
314 /* Consider delete protected file/dir 'deleted' */
315 deletedfile = TRUE;
317 if (force)
318 SetProtection(ap->ap_Buf, 0);
319 else
321 Printf("%s Not Deleted", (ULONG)ap->ap_Buf);
322 PrintFault(ERROR_DELETE_PROTECTED, "");
323 deleteit = FALSE;
326 isfile = !isDirectory(ap, forcelinks);
327 strcpy(name, ap->ap_Buf);
329 MatchEnd(ap);
330 if (deleteit)
332 /* Try to delete the file or directory */
333 if (!DeleteFile(name))
335 LONG ioerr = IoErr();
336 Printf("%s Not Deleted", (ULONG)name);
337 PrintFault(ioerr, "");
339 else if (!quiet)
341 Printf("%s Deleted\n", (ULONG)name);
344 deletedfile = TRUE;
345 deleteit = FALSE;
349 if (firstmatch && match &&
350 match != ERROR_OBJECT_NOT_FOUND &&
351 match != ERROR_NO_MORE_ENTRIES)
353 PrintFault(match, NULL);
354 return RETURN_WARN;
357 if (!deletedfile)
359 PutStr("No file to delete\n");
360 return RETURN_WARN;
362 return RETURN_OK;