Dereference symlinks when copying.
[tangerine.git] / workbench / c / Rename.c
blobc7d465d65271ce8a3f213cc5bdc7c4347be5cf5d
1 /*
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
3 $Id$
5 Rename CLI command.
6 */
8 /*****************************************************************************
10 NAME
12 Rename
14 SYNOPSIS
16 Rename [{FROM}] <name> [TO|AS] <name> [QUIET]
18 FROM/A/M,TO=AS/A,QUIET/S
20 LOCATION
22 Sys:c
24 FUNCTION
26 Renames a directory or file. Rename can also act like the UNIX mv
27 command, which moves a file or files to another location on disk.
29 INPUTS
31 FROM -- The name(s) of the file(s) to rename or move. There may
32 be many files specified, this is used when moving files
33 into a new directory.
35 TO|AS -- The name which we wish to call the file.
37 QUIET -- Suppress any output from the command.
39 RESULT
41 Standard DOS error codes.
43 NOTES
45 EXAMPLE
47 Rename letter1.doc letter2.doc letters
49 Moves letter1.doc and letter2.doc to the directory letters.
51 Rename ram:a ram:b quiet
52 Rename from ram:a to ram:b quiet
53 Rename from=ram:a to=ram:b quiet
55 All versions, renames file "a" to "b" and does not output any
56 diagnostic information.
58 BUGS
60 SEE ALSO
62 INTERNALS
64 Rename() can only move a file to another directory, if and only if
65 the to path has the from filename appended to the end.
67 e.g.
68 Rename("ram:a", "ram:clipboards/a");
69 not
70 Rename("ram:a", "ram:clipboards/");
72 ******************************************************************************/
74 #define DEBUG 0
75 #include <aros/debug.h>
77 #include <proto/dos.h>
78 #include <proto/exec.h>
80 #include <dos/dos.h>
81 #include <dos/dosasl.h>
82 #include <dos/rdargs.h>
83 #include <exec/memory.h>
84 #include <exec/types.h>
86 #include <stdio.h>
87 #include <string.h>
89 #define ARG_TEMPLATE "FROM/A/M,TO=AS/A,QUIET/S"
91 #define APPNAME "Rename"
93 enum
95 ARG_FROM,
96 ARG_TO,
97 ARG_QUIET,
98 NOOFARGS
102 #define MAX_PATH_LEN 2048
104 const TEXT version[] = "$VER: Rename 41.2 (23.11.2000)\n";
107 int doRename(STRPTR *from, STRPTR to, BOOL quiet);
110 int __nocommandline;
112 int main(void)
114 struct RDArgs *rda;
116 IPTR args[NOOFARGS] = { (IPTR) NULL, (IPTR) NULL, FALSE };
118 int retval = RETURN_FAIL;
120 rda = ReadArgs(ARG_TEMPLATE, args, NULL);
122 if(rda != NULL)
124 STRPTR *from = (STRPTR *)args[ARG_FROM];
125 STRPTR to = (STRPTR)args[ARG_TO];
126 BOOL quiet = args[ARG_QUIET] != 0;
128 retval = doRename(from, to, quiet);
130 FreeArgs(rda);
132 else
134 PrintFault(IoErr(), APPNAME);
135 retval = RETURN_ERROR;
138 return retval;
142 int doRename(STRPTR *from, STRPTR to, BOOL quiet)
144 #define ERROR(n) retval = (n); goto cleanup
146 struct AnchorPath *ap;
148 UBYTE *pathName;
149 STRPTR fileStart;
150 BOOL destIsDir = FALSE;
151 BOOL destExists = FALSE;
152 LONG match;
153 BPTR tolock = NULL;
154 ULONG i;
155 int retval;
156 LONG ioerr = 0;
157 UBYTE itsWild;
158 BOOL isSingle;
160 ap = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath) + MAX_PATH_LEN + MAX_PATH_LEN,
161 MEMF_ANY | MEMF_CLEAR);
162 if (!ap)
164 ioerr = IoErr();
165 ERROR(RETURN_FAIL);
168 pathName = ((UBYTE *) (ap + 1)) + MAX_PATH_LEN;
170 ap->ap_BreakBits = SIGBREAKF_CTRL_C;
171 ap->ap_Flags = APF_DOWILD;
172 ap->ap_Strlen = MAX_PATH_LEN;
173 if (MatchFirst(from[0], ap) != 0)
175 ioerr = IoErr();
176 if (ioerr == ERROR_OBJECT_NOT_FOUND)
178 Printf("Can't rename %s as %s because ", from[0], to);
180 ERROR(RETURN_FAIL);
182 itsWild = ap->ap_Flags & APF_ITSWILD;
183 MatchEnd(ap);
185 /* First we check if the destination is a directory */
186 tolock = Lock(to, SHARED_LOCK);
187 if (tolock)
189 struct FileInfoBlock *fib = AllocDosObject(DOS_FIB, NULL);
190 LONG entrytype;
192 destExists = TRUE;
194 if (!fib)
196 PrintFault(IoErr(), APPNAME);
198 ERROR(RETURN_FAIL);
201 i = Examine(tolock, fib);
202 entrytype = fib->fib_EntryType;
203 FreeDosObject(DOS_FIB, fib);
205 if (i)
207 if (entrytype >= 0)
209 destIsDir = TRUE;
212 else
214 PrintFault(IoErr(), APPNAME);
216 ERROR(RETURN_FAIL);
221 /* Check if dest is not a dir and src is pattern or multi */
222 if (!destIsDir && (itsWild || from[1]))
224 Printf("Destination \"%s\" is not a directory.\n", to);
225 ERROR(RETURN_FAIL);
229 /* Handle single file name change */
230 isSingle =!destIsDir;
231 /* 15th Jan 2004 bugfix, (destIsDir && ...) not (!destisDir && ...) ! - Piru */
232 if (destIsDir && !from[1])
234 BPTR fromlock;
236 fromlock = Lock(from[0], ACCESS_READ);
237 if (fromlock)
239 isSingle = SameLock(fromlock, tolock) == LOCK_SAME;
241 UnLock(fromlock);
244 /* 4th May 2003 bugfix: be quiet about single object renames - Piru */
245 quiet = TRUE;
247 if (isSingle)
249 if (ParsePattern(from[0], pathName, MAX_PATH_LEN) > -1 &&
250 Rename(pathName, to))
252 ERROR(RETURN_OK);
255 ioerr = IoErr();
256 Printf("Can't rename %s as %s because ", from[0], to);
257 ERROR(RETURN_FAIL);
260 if (tolock)
262 if (!NameFromLock(tolock, pathName, MAX_PATH_LEN))
264 if (IoErr() == ERROR_LINE_TOO_LONG)
266 PrintFault(IoErr(), APPNAME);
268 ERROR(RETURN_FAIL);
271 pathName[0] = '\0';
275 if (!pathName[0])
277 stccpy(pathName, to, MAX_PATH_LEN);
281 /* Now either only one specific file should be renamed or the
282 destination is really a directory. We can use the same routine
283 for both cases! */
285 fileStart = pathName + strlen(pathName);
287 ap->ap_BreakBits = SIGBREAKF_CTRL_C;
288 ap->ap_Strlen = MAX_PATH_LEN;
290 for (i = 0; from[i]; i++)
292 for (match = MatchFirst(from[i], ap); match == 0; match = MatchNext(ap))
294 /* Check for identical 'from' and 'to'? */
296 if (destIsDir)
298 /* Clear former filename */
299 *fileStart = '\0';
300 if (!AddPart(pathName, FilePart(ap->ap_Buf), MAX_PATH_LEN))
302 MatchEnd(ap);
304 PrintFault(ERROR_LINE_TOO_LONG, APPNAME);
305 SetIoErr(ERROR_LINE_TOO_LONG);
307 ERROR(RETURN_FAIL);
311 if (!quiet)
313 Printf("Renaming %s as %s\n", ap->ap_Buf, pathName);
316 if (!Rename(ap->ap_Buf, pathName))
318 ioerr = IoErr();
319 MatchEnd(ap);
321 Printf("Can't rename %s as %s because ", ap->ap_Buf, pathName);
322 ERROR(RETURN_FAIL);
326 MatchEnd(ap);
329 if (ap->ap_FoundBreak & SIGBREAKF_CTRL_C)
331 PrintFault(ERROR_BREAK, NULL);
333 retval = RETURN_WARN;
335 else
337 retval = RETURN_OK;
340 cleanup:
341 if (tolock)
343 UnLock(tolock);
346 if (ioerr)
348 //MatchEnd(ap);
349 PrintFault(ioerr, NULL);
350 SetIoErr(ioerr);
351 //retval = ERROR_FAIL;
354 FreeVec(ap);
356 return retval;