prism2.device: Compiler delint
[AROS.git] / workbench / c / Delete.c
blobd21a6dd5f6d521ff3ad0cd43e94f28166b0c4b91
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 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 /* Try to delete the file or directory */
256 if (!DeleteFile(name))
258 LONG ioerr = IoErr();
259 Printf("%s Not Deleted", (IPTR)name);
260 PrintFault(ioerr, "");
262 else if (!quiet)
264 Printf("%s Deleted\n", (IPTR)name);
267 deletedfile = TRUE;
268 deleteit = FALSE;
271 /* If this is a directory, we enter it regardless if the ALL
272 switch is set. */
273 if (isDirectory(ap, forcelinks))
275 /* This is a directory. It's important to check if we just left
276 the directory or is about to enter it. This is because we
277 cannot delete a directory until we have deleted all the
278 files in it. */
279 if (ap->ap_Flags & APF_DIDDIR)
281 /* If we get here, we are in ALL mode and have deleted
282 all the files inside the dir (if none were protected
283 and such). */
285 ap->ap_Flags &= ~APF_DIDDIR;
287 /* Now go on and delete the directory */
289 else
291 /* We stumbled upon a directory */
293 if(all)
295 ap->ap_Flags |= APF_DODIR;
297 /* We don't want to delete a directory before deleting
298 possible files inside it. Thus, match next file */
299 continue;
302 /* If all is not set, DeleteFile() will return an error
303 in case the directory was not empty. */
306 /* Mark the entry for deletion */
307 deleteit = TRUE;
309 /* Check permissions */
310 if (!isDeletable(&ap->ap_Info))
312 /* Consider delete protected file/dir 'deleted' */
313 deletedfile = TRUE;
315 if (force)
316 SetProtection(ap->ap_Buf, 0);
317 else
319 Printf("%s Not Deleted", (IPTR)ap->ap_Buf);
320 PrintFault(ERROR_DELETE_PROTECTED, "");
321 deleteit = FALSE;
324 strcpy(name, ap->ap_Buf);
326 MatchEnd(ap);
327 if (deleteit)
329 /* Try to delete the file or directory */
330 if (!DeleteFile(name))
332 LONG ioerr = IoErr();
333 Printf("%s Not Deleted", (IPTR)name);
334 PrintFault(ioerr, "");
336 else if (!quiet)
338 Printf("%s Deleted\n", (IPTR)name);
341 deletedfile = TRUE;
342 deleteit = FALSE;
346 if (firstmatch && match &&
347 match != ERROR_OBJECT_NOT_FOUND &&
348 match != ERROR_NO_MORE_ENTRIES)
350 PrintFault(match, NULL);
351 return RETURN_WARN;
354 if (!deletedfile)
356 PutStr("No file to delete\n");
357 return RETURN_WARN;
359 return RETURN_OK;