2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
8 /*****************************************************************************
16 Delete { (name | pattern) } [ALL] [QUIET] [FORCE]
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
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
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.
60 Shows a good usage of the pattern matching capabilities.
62 ******************************************************************************/
64 #include <proto/dos.h>
65 #include <proto/exec.h>
68 #include <dos/dosasl.h>
69 #include <exec/memory.h>
74 #define ARG_TEMPLATE "FILE/M/A,ALL/S,QUIET/S,FORCE/S,FOLLOWLINKS/S"
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
);
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
);
111 ap
->ap_Strlen
= MAX_PATH_LEN
;
113 rda
= ReadArgs(ARG_TEMPLATE
, args
, 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
);
130 PrintFault(IoErr(), cmdname
);
131 retval
= RETURN_FAIL
;
136 retval
= RETURN_FAIL
;
144 static inline BOOL
isDirectory(struct AnchorPath
*ap
, BOOL followflag
)
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
160 /* Okay flag set, figure out if this is a softlink to directory
164 lock
= Lock(ap
->ap_Buf
, ACCESS_READ
);
167 struct FileInfoBlock
*fib
;
169 fib
= AllocDosObject(DOS_FIB
, NULL
);
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
);
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
197 isdir
= ap
->ap_Info
.fib_DirEntryType
>= 0;
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
)
209 char name
[MAX_PATH_LEN
];
210 BOOL deleteit
= FALSE
;
211 BOOL deletedfile
= FALSE
;
212 BOOL firstmatch
= TRUE
;
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
))
231 UnLockDosList(LDF_ALL
| LDF_READ
);
233 Printf("%s is a device and cannot be deleted\n", files
[i
]);
237 UnLockDosList(LDF_ALL
| LDF_READ
);
240 for (match
= MatchFirst(files
[i
], ap
); match
== 0;
241 match
= MatchNext(ap
))
245 if (CheckSignal(SIGBREAKF_CTRL_C
))
248 PrintFault(ERROR_BREAK
,"");
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
, "");
268 Printf("%s Deleted\n", (IPTR
)name
);
274 /* If this is a directory, we enter it regardless if the ALL
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
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
288 ap
->ap_Flags
&= ~APF_DIDDIR
;
290 /* Now go on and delete the directory */
294 /* We stumbled upon a directory */
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 */
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 */
312 /* Check permissions */
313 if (!isDeletable(&ap
->ap_Info
))
315 /* Consider delete protected file/dir 'deleted' */
319 SetProtection(ap
->ap_Buf
, 0);
322 Printf("%s Not Deleted", (IPTR
)ap
->ap_Buf
);
323 PrintFault(ERROR_DELETE_PROTECTED
, "");
327 strcpy(name
, ap
->ap_Buf
);
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
)
349 Printf("%s Deleted\n", (IPTR
)name
);
356 if (firstmatch
&& match
&&
357 match
!= ERROR_OBJECT_NOT_FOUND
&&
358 match
!= ERROR_NO_MORE_ENTRIES
)
360 PrintFault(match
, NULL
);
366 PutStr("No file to delete\n");