2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: fsrtns.c /main/6 1998/10/26 12:41:20 mgreess $ */
24 /************************************<+>*************************************
25 ****************************************************************************
30 * DESCRIPTION: Routines to manipulate files and directores
45 * (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
46 * (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
47 * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
48 * (c) Copyright 1993, 1994, 1995 Novell, Inc.
50 ****************************************************************************
51 ************************************<+>*************************************/
56 #include <sys/types.h>
68 /*--------------------------------------------------------------------
70 *------------------------------------------------------------------*/
72 int (*progressCallback)(char *fname) = NULL;
73 int (*errorCallback)(char *fname, int errnum) = NULL;
74 int (*periodicCallback)() = NULL;
76 /*--------------------------------------------------------------------
78 *------------------------------------------------------------------*/
80 static int CopyObject(char *sourceP, char *targetP, int repl, int link);
81 static int EraseObject(char *nameP, int force);
85 CopyFile(char *sourceP, char *targetP, int repl, struct stat *statP)
86 /* copy a file; if repl non-zero, overwrite any existing file */
94 /* open source file for read */
95 src = open(sourceP, O_RDONLY, 0);
99 /* create target file */
100 tgt = open(targetP, O_CREAT | O_EXCL | O_WRONLY, statP->st_mode & 0777);
101 if (tgt < 0 && errno == EEXIST && repl) {
102 rc = EraseObject(targetP, repl);
107 tgt = open(targetP, O_CREAT | O_EXCL | O_WRONLY, statP->st_mode & 0777);
115 /* if we have root privileges, make sure file ownership is preserved */
116 if (geteuid() == 0) {
117 if (statP->st_uid != 0 || statP->st_gid != getegid()) {
118 rc = fchown(tgt, statP->st_uid, statP->st_gid);
130 /* read data from source file */
133 nread = read(src, buffer, sizeof(buffer));
134 } while (nread < 0 && errno == EINTR);
138 /* write data to target file */
141 nwrite = write(tgt, buffer, nread);
142 } while (nwrite < 0 && errno == EINTR);
146 if (periodicCallback)
147 if (periodicCallback() != 0) {
155 /* check if data copy ended abnormally */
156 rc = (nread == 0)? 0: (errno != 0)? errno: -1;
168 /* set target file attributes */
169 ut.actime = statP->st_atime;
170 ut.modtime = statP->st_mtime;
171 rc = utime(targetP, &ut);
173 return (rc != 0)? errno: 0;
178 CopyLink(char *sourceP, char *targetP, int repl, struct stat *statP)
179 /* copy a symbolic link */
186 l = readlink(sourceP, buf, sizeof(buf));
187 } while (l < 0 && errno == EINTR);
191 if (symlink(buf, targetP) == 0)
193 else if (errno != EEXIST || !repl)
196 if ((rc = EraseObject(targetP, repl)) != 0)
198 if (symlink(buf, targetP) == 0)
206 CopyDir(char *sourceP, char *targetP, int repl, int link, struct stat *statP)
207 /* copy a directory and recursively all its subdirectories */
209 DIR *dirP; /* open directory */
210 struct dirent *entryP; /* directory entry */
211 char srcname[1024], tgtname[1024];
215 /* open source directory */
216 dirP = opendir(sourceP);
220 /* create target directory */
221 rc = mkdir(targetP, statP->st_mode & 0777);
222 if (rc < 0 && errno == EEXIST && repl) {
223 rc = EraseObject(targetP, repl);
226 rc = mkdir(targetP, statP->st_mode & 0777);
234 /* if we have root privileges, make sure directory ownership is preserved */
235 if (geteuid() == 0) {
236 if (statP->st_uid != 0 || statP->st_gid != getegid()) {
237 rc = chown(targetP, statP->st_uid, statP->st_gid);
246 /* prepare source and target names */
247 strcpy(srcname, sourceP);
248 srclen = strlen(srcname);
249 if (srcname[srclen - 1] != '/')
250 srcname[srclen++] = '/';
251 strcpy(tgtname, targetP);
252 tgtlen = strlen(tgtname);
253 if (tgtname[tgtlen - 1] != '/')
254 tgtname[tgtlen++] = '/';
256 for (rc = 0; rc == 0; ) {
259 entryP = readdir(dirP);
260 } while (entryP == NULL && errno == EINTR);
261 if (entryP == NULL) {
265 if (strcmp(entryP->d_name, ".") == 0 || strcmp(entryP->d_name, "..") == 0)
268 strcpy(srcname + srclen, entryP->d_name);
269 strcpy(tgtname + tgtlen, entryP->d_name);
271 rc = CopyObject(srcname, tgtname, repl, link);
280 CopyObject(char *sourceP, char *targetP, int repl, int link)
281 /* copy a directory, file, or symbolic link */
283 struct stat src_stat;
286 if (progressCallback)
287 if (progressCallback(sourceP) != 0)
290 if (periodicCallback)
291 if (periodicCallback() != 0)
294 if (lstat(sourceP, &src_stat) < 0)
301 switch(src_stat.st_mode & S_IFMT) {
304 rc = CopyDir(sourceP, targetP, repl, link, &src_stat);
308 rc = CopyFile(sourceP, targetP, repl, &src_stat);
313 rc = CopyLink(sourceP, targetP, repl, &src_stat);
314 else if (stat(sourceP, &src_stat) < 0)
326 * Return code zero means everything is ok;
327 * return code -1 means the operation is aborted.
328 * In either case, propagated the return code up.
334 * Return code > 0 means an error occurred in the last operation.
335 * Call the the error callback function. If the callback returns
336 * zero, we return zero; this will cause the error to be ignored.
337 * Otherwise we return -1 to signal that the operation is aborted.
341 else if (errorCallback(sourceP, rc) == 0)
349 EmptyDir(char *sourceP, int rm, int force)
351 DIR *dirP; /* open directory */
352 struct dirent *entryP; /* directory entry */
357 /* open source directory */
358 dirP = opendir(sourceP);
362 /* prepare source name */
363 strcpy(srcname, sourceP);
364 srclen = strlen(srcname);
365 if (srcname[srclen - 1] != '/')
366 srcname[srclen++] = '/';
369 while (rc == 0 && (entryP = readdir(dirP)) != NULL) {
370 if (strcmp(entryP->d_name, ".") == 0 || strcmp(entryP->d_name, "..") == 0)
372 strcpy(srcname + srclen, entryP->d_name);
373 rc = EraseObject(srcname, force);
387 EraseObject(char *nameP, int force)
389 struct stat src_stat;
392 if (periodicCallback)
393 if (periodicCallback() != 0)
396 if (lstat(nameP, &src_stat) < 0)
398 else if ((src_stat.st_mode & S_IFMT) == S_IFDIR) {
399 if (! access(nameP, X_OK|W_OK))
401 rc = EmptyDir(nameP, 1, force);
404 if (! (force || access(nameP, W_OK)))
412 * Return code zero means everything is ok;
413 * return code -1 means the operation is aborted.
414 * In either case, propagated the return code up.
420 * Return code > 0 means an error occurred in the last operation.
421 * Call the the error callback function. If the callback returns
422 * zero, we return zero; this will cause the error to be ignored.
423 * Otherwise we return -1 to signal that the operation is aborted.
427 else if (errorCallback(nameP, rc) == 0)
433 /*--------------------------------------------------------------------
435 *------------------------------------------------------------------*/
438 fsRename(char *sourceP, char *targetP, int replace, int *rcP)
444 /* return error if target file already exists */
445 rc = lstat(targetP, &buf);
449 } else if (errno != ENOENT) {
454 *rcP = rename(sourceP, targetP);
458 if (replace && *rcP == ENOTDIR || *rcP == EISDIR) {
459 /* error reason: tried to replace file by directory or vice versa */
460 *rcP = EraseObject(targetP, replace);
463 *rcP = rename(sourceP, targetP);
471 fsMove(char *sourceP, char *targetP, int replace, int *rcP)
474 fsRename(sourceP, targetP, replace, rcP);
475 if (*rcP == 0 || *rcP != EXDEV)
478 /* source and target on different file systems: do copy + erase */
480 /* first check if we have write permission in the source directory */
483 strcpy(dir, sourceP);
484 p = strrchr(dir, '/');
492 if (access(dir, W_OK) != 0) {
498 *rcP = CopyObject(sourceP, targetP, replace, 1);
501 *rcP = EraseObject(sourceP, replace);
506 fsCopy(char *sourceP, char *targetP, int replace, int *rcP)
508 *rcP = CopyObject(sourceP, targetP, replace, 0);
513 fsCopyLink(char *sourceP, char *targetP, int replace, int *rcP)
515 *rcP = CopyObject(sourceP, targetP, replace, 1);
520 fsErase(char *nameP, int *rcP, int force)
522 *rcP = EraseObject(nameP, force);
527 fsEmpty(char *nameP, int *rcP)
529 *rcP = EmptyDir(nameP, 0, 0);