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>
75 #define ARG_TEMPLATE "FILE/M/A,ALL/S,QUIET/S,FORCE/S,FOLLOWLINKS/S"
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
);
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
);
112 ap
->ap_Strlen
= MAX_PATH_LEN
;
114 rda
= ReadArgs(ARG_TEMPLATE
, args
, 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
);
131 PrintFault(IoErr(), cmdname
);
132 retval
= RETURN_FAIL
;
137 retval
= RETURN_FAIL
;
145 static inline BOOL
isDirectory(struct AnchorPath
*ap
, BOOL followflag
)
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
161 /* Okay flag set, figure out if this is a softlink to directory
165 lock
= Lock(ap
->ap_Buf
, ACCESS_READ
);
168 struct FileInfoBlock
*fib
;
170 fib
= AllocDosObject(DOS_FIB
, NULL
);
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
);
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
198 isdir
= ap
->ap_Info
.fib_DirEntryType
>= 0;
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
)
210 char name
[MAX_PATH_LEN
];
212 BOOL deleteit
= FALSE
;
213 BOOL deletedfile
= FALSE
;
214 BOOL firstmatch
= TRUE
;
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
))
234 UnLockDosList(LDF_ALL
| LDF_READ
);
236 Printf("%s is a device and cannot be deleted\n", files
[i
]);
240 UnLockDosList(LDF_ALL
| LDF_READ
);
243 for (match
= MatchFirst(files
[i
], ap
); match
== 0;
244 match
= MatchNext(ap
))
248 if (CheckSignal(SIGBREAKF_CTRL_C
))
251 PrintFault(ERROR_BREAK
,"");
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
, "");
267 Printf("%s Deleted\n", (ULONG
)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", (ULONG
)ap
->ap_Buf
);
323 PrintFault(ERROR_DELETE_PROTECTED
, "");
327 isfile
= !isDirectory(ap
, forcelinks
);
328 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", (ULONG
)name
);
338 PrintFault(ioerr
, "");
342 Printf("%s Deleted\n", (ULONG
)name
);
350 if (firstmatch
&& match
&&
351 match
!= ERROR_OBJECT_NOT_FOUND
&&
352 match
!= ERROR_NO_MORE_ENTRIES
)
354 PrintFault(match
, NULL
);
360 PutStr("No file to delete\n");