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
;
221 for (i
= 0; files
[i
] != NULL
; i
++)
223 /* Index for last character in the current file name (pattern name) */
224 int lastIndex
= strlen(files
[i
]) - 1;
226 if (files
[i
][lastIndex
] == ':')
228 struct DosList
*dl
= LockDosList(LDF_ALL
| LDF_READ
);
230 if (FindDosEntry(dl
, (CONST_STRPTR
)files
[i
], LDF_ALL
| LDF_READ
))
233 UnLockDosList(LDF_ALL
| LDF_READ
);
235 Printf("%s is a device and cannot be deleted\n", files
[i
]);
239 UnLockDosList(LDF_ALL
| LDF_READ
);
242 for (match
= MatchFirst(files
[i
], ap
); match
== 0;
243 match
= MatchNext(ap
))
247 if (CheckSignal(SIGBREAKF_CTRL_C
))
250 PrintFault(ERROR_BREAK
,"");
257 /* Try to delete the file or directory */
258 if (!DeleteFile(name
))
260 LONG ioerr
= IoErr();
261 Printf("%s Not Deleted", (ULONG
)name
);
262 PrintFault(ioerr
, "");
266 Printf("%s Deleted\n", (ULONG
)name
);
273 /* If this is a directory, we enter it regardless if the ALL
275 if (isDirectory(ap
, forcelinks
))
277 /* This is a directory. It's important to check if we just left
278 the directory or is about to enter it. This is because we
279 cannot delete a directory until we have deleted all the
281 if (ap
->ap_Flags
& APF_DIDDIR
)
283 /* If we get here, we are in ALL mode and have deleted
284 all the files inside the dir (if none were protected
287 ap
->ap_Flags
&= ~APF_DIDDIR
;
289 /* Now go on and delete the directory */
293 /* We stumbled upon a directory */
297 ap
->ap_Flags
|= APF_DODIR
;
299 /* We don't want to delete a directory before deleting
300 possible files inside it. Thus, match next file */
304 /* If all is not set, DeleteFile() will return an error
305 in case the directory was not empty. */
308 /* Mark the entry for deletion */
311 /* Check permissions */
312 if (!isDeletable(&ap
->ap_Info
))
314 /* Consider delete protected file/dir 'deleted' */
318 SetProtection(ap
->ap_Buf
, 0);
321 Printf("%s Not Deleted", (ULONG
)ap
->ap_Buf
);
322 PrintFault(ERROR_DELETE_PROTECTED
, "");
326 isfile
= !isDirectory(ap
, forcelinks
);
327 strcpy(name
, ap
->ap_Buf
);
332 /* Try to delete the file or directory */
333 if (!DeleteFile(name
))
335 LONG ioerr
= IoErr();
336 Printf("%s Not Deleted", (ULONG
)name
);
337 PrintFault(ioerr
, "");
341 Printf("%s Deleted\n", (ULONG
)name
);
349 if (firstmatch
&& match
&&
350 match
!= ERROR_OBJECT_NOT_FOUND
&&
351 match
!= ERROR_NO_MORE_ENTRIES
)
353 PrintFault(match
, NULL
);
359 PutStr("No file to delete\n");