exec.library: Allocate/Deallocate functions must remain generic and not handler MemHe...
[AROS.git] / workbench / c / Delete.c
blobbcd3ac493d8dbfd03e9517824fb38ca1e689a928
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.2 (6.1.2000)\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 if (!(quiet))
234 Printf("%s is a device and cannot be deleted\n", files[i]);
236 return RETURN_FAIL;
238 UnLockDosList(LDF_ALL | LDF_READ);
241 for (match = MatchFirst(files[i], ap); match == 0;
242 match = MatchNext(ap))
244 firstmatch = FALSE;
246 if (CheckSignal(SIGBREAKF_CTRL_C))
248 MatchEnd(ap);
249 PrintFault(ERROR_BREAK,"");
251 return RETURN_ERROR;
254 if (deleteit)
256 deletedfile = FALSE;
257 /* Try to delete the file or directory */
258 if (!DeleteFile(name))
260 if (!quiet)
262 LONG ioerr = IoErr();
263 Printf("%s Not Deleted", (IPTR)name);
264 PrintFault(ioerr, "");
267 else
269 deletedfile = TRUE;
270 if (!quiet)
272 Printf("%s Deleted\n", (IPTR)name);
275 deleteit = FALSE;
278 /* If this is a directory, we enter it regardless if the ALL
279 switch is set. */
280 if (isDirectory(ap, forcelinks))
282 /* This is a directory. It's important to check if we just left
283 the directory or is about to enter it. This is because we
284 cannot delete a directory until we have deleted all the
285 files in it. */
286 if (ap->ap_Flags & APF_DIDDIR)
288 /* If we get here, we are in ALL mode and have deleted
289 all the files inside the dir (if none were protected
290 and such). */
292 ap->ap_Flags &= ~APF_DIDDIR;
294 /* Now go on and delete the directory */
296 else
298 /* We stumbled upon a directory */
300 if(all)
302 ap->ap_Flags |= APF_DODIR;
304 /* We don't want to delete a directory before deleting
305 possible files inside it. Thus, match next file */
306 continue;
309 /* If all is not set, DeleteFile() will return an error
310 in case the directory was not empty. */
313 /* Mark the entry for deletion */
314 deleteit = TRUE;
316 /* Check permissions */
317 if (!isDeletable(&ap->ap_Info))
319 /* Consider delete protected file/dir 'deleted' */
320 deletedfile = TRUE;
322 if (force)
323 SetProtection(ap->ap_Buf, 0);
324 else
326 if (!quiet)
328 Printf("%s Not Deleted", (IPTR)ap->ap_Buf);
329 PrintFault(ERROR_DELETE_PROTECTED, "");
331 deleteit = FALSE;
334 strcpy(name, ap->ap_Buf);
336 MatchEnd(ap);
337 if (deleteit)
339 deletedfile = FALSE;
340 /* Try to delete the file or directory */
341 if (!DeleteFile(name))
343 if (!quiet)
345 LONG ioerr = IoErr();
346 Printf("%s Not Deleted", (IPTR)name);
347 PrintFault(ioerr, "");
350 else
352 deletedfile = TRUE;
353 if (!quiet)
356 Printf("%s Deleted\n", (IPTR)name);
359 deleteit = FALSE;
363 if (firstmatch && match &&
364 match != ERROR_OBJECT_NOT_FOUND &&
365 match != ERROR_NO_MORE_ENTRIES)
367 PrintFault(match, NULL);
368 return RETURN_WARN;
371 if (!deletedfile)
373 if (!quiet)
375 PutStr("No file to delete\n");
377 return RETURN_WARN;
379 return RETURN_OK;