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.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
);
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
);
234 Printf("%s is a device and cannot be deleted\n", files
[i
]);
238 UnLockDosList(LDF_ALL
| LDF_READ
);
241 for (match
= MatchFirst(files
[i
], ap
); match
== 0;
242 match
= MatchNext(ap
))
246 if (CheckSignal(SIGBREAKF_CTRL_C
))
249 PrintFault(ERROR_BREAK
,"");
257 /* Try to delete the file or directory */
258 if (!DeleteFile(name
))
262 LONG ioerr
= IoErr();
263 Printf("%s Not Deleted", (IPTR
)name
);
264 PrintFault(ioerr
, "");
272 Printf("%s Deleted\n", (IPTR
)name
);
278 /* If this is a directory, we enter it regardless if the ALL
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
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
292 ap
->ap_Flags
&= ~APF_DIDDIR
;
294 /* Now go on and delete the directory */
298 /* We stumbled upon a directory */
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 */
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 */
316 /* Check permissions */
317 if (!isDeletable(&ap
->ap_Info
))
319 /* Consider delete protected file/dir 'deleted' */
323 SetProtection(ap
->ap_Buf
, 0);
328 Printf("%s Not Deleted", (IPTR
)ap
->ap_Buf
);
329 PrintFault(ERROR_DELETE_PROTECTED
, "");
334 strcpy(name
, ap
->ap_Buf
);
340 /* Try to delete the file or directory */
341 if (!DeleteFile(name
))
345 LONG ioerr
= IoErr();
346 Printf("%s Not Deleted", (IPTR
)name
);
347 PrintFault(ioerr
, "");
356 Printf("%s Deleted\n", (IPTR
)name
);
363 if (firstmatch
&& match
&&
364 match
!= ERROR_OBJECT_NOT_FOUND
&&
365 match
!= ERROR_NO_MORE_ENTRIES
)
367 PrintFault(match
, NULL
);
375 PutStr("No file to delete\n");