added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / workbench / c / Delete.c
blobc145020e6730281bf06c6b9b33a4be56121412a7
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;
215 STRPTR file;
217 if (!files)
219 return RETURN_OK;
222 for (i = 0; files[i] != NULL; i++)
224 /* Index for last character in the current file name (pattern name) */
225 int lastIndex = strlen(files[i]) - 1;
227 if (files[i][lastIndex] == ':')
229 struct DosList *dl = LockDosList(LDF_ALL | LDF_READ);
231 if (FindDosEntry(dl, (CONST_STRPTR)files[i], LDF_ALL | LDF_READ))
233 MatchEnd(ap);
234 UnLockDosList(LDF_ALL | LDF_READ);
236 Printf("%s is a device and cannot be deleted\n", files[i]);
238 return RETURN_FAIL;
240 UnLockDosList(LDF_ALL | LDF_READ);
243 for (match = MatchFirst(files[i], ap); match == 0;
244 match = MatchNext(ap))
246 firstmatch = FALSE;
248 if (CheckSignal(SIGBREAKF_CTRL_C))
250 MatchEnd(ap);
251 PrintFault(ERROR_BREAK,"");
253 return RETURN_ERROR;
256 if (deleteit)
258 /* Try to delete the file or directory */
259 if (!DeleteFile(name))
261 LONG ioerr = IoErr();
262 Printf("%s Not Deleted", (ULONG)name);
263 PrintFault(ioerr, "");
265 else if (!quiet)
267 Printf("%s Deleted\n", (ULONG)name);
270 deletedfile = TRUE;
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", (ULONG)ap->ap_Buf);
323 PrintFault(ERROR_DELETE_PROTECTED, "");
324 deleteit = FALSE;
327 isfile = !isDirectory(ap, forcelinks);
328 strcpy(name, ap->ap_Buf);
330 MatchEnd(ap);
331 if (deleteit)
333 /* Try to delete the file or directory */
334 if (!DeleteFile(name))
336 LONG ioerr = IoErr();
337 Printf("%s Not Deleted", (ULONG)name);
338 PrintFault(ioerr, "");
340 else if (!quiet)
342 Printf("%s Deleted\n", (ULONG)name);
345 deletedfile = TRUE;
346 deleteit = FALSE;
350 if (firstmatch && match &&
351 match != ERROR_OBJECT_NOT_FOUND &&
352 match != ERROR_NO_MORE_ENTRIES)
354 PrintFault(match, NULL);
355 return RETURN_WARN;
358 if (!deletedfile)
360 PutStr("No file to delete\n");
361 return RETURN_WARN;
363 return RETURN_OK;