XRootD
Loading...
Searching...
No Matches
XrdOssCopy.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d O s s C o p y . c c */
4/* */
5/* (c) 2009 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* All Rights Reserved */
7/* Produced by Andrew Hanushevsky for Stanford University under contract */
8/* DE-AC02-76-SFO0515 with the Department of Energy */
9/* */
10/* This file is part of the XRootD software suite. */
11/* */
12/* XRootD is free software: you can redistribute it and/or modify it under */
13/* the terms of the GNU Lesser General Public License as published by the */
14/* Free Software Foundation, either version 3 of the License, or (at your */
15/* option) any later version. */
16/* */
17/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20/* License for more details. */
21/* */
22/* You should have received a copy of the GNU Lesser General Public License */
23/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25/* */
26/* The copyright holder's institutional names and contributor's names may not */
27/* be used to endorse or promote products derived from this software without */
28/* specific prior written permission of the institution or contributor. */
29/******************************************************************************/
30
31#include <cerrno>
32#include <fcntl.h>
33#include <cstring>
34#include <ctime>
35#include <cstdio>
36#include <unistd.h>
37#include <utime.h>
38#include <sys/mman.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41
42#include "XrdOss/XrdOssCopy.hh"
43#include "XrdOss/XrdOssTrace.hh"
44#include "XrdSys/XrdSysError.hh"
45#include "XrdSys/XrdSysFAttr.hh"
46
47/******************************************************************************/
48/* E r r o r R o u t i n g O b j e c t */
49/******************************************************************************/
50
52
54
55/******************************************************************************/
56/* Public: C o p y */
57/******************************************************************************/
58
59off_t XrdOssCopy::Copy(const char *inFn, const char *outFn, int outFD)
60{
61 static const size_t segSize = 1024*1024;
62 class ioFD
63 {public:
64 int FD;
65 ioFD(int fd=-1) : FD(fd) {}
66 ~ioFD() {if (FD >= 0) close(FD);}
67 } In, Out(outFD);
68
69 struct utimbuf tBuff;
70 struct stat buf, bufO, bufSL;
71 char *inBuff, *bP;
72 off_t Offset=0, fileSize;
73 size_t ioSize, copySize;
74 ssize_t rLen;
75 int rc;
76
77// Open the input file
78//
79 if ((In.FD = open(inFn, O_RDONLY)) < 0)
80 return -OssEroute.Emsg("Copy", errno, "open", inFn);
81
82// Get the input filesize
83//
84 if (fstat(In.FD, &buf)) return -OssEroute.Emsg("Copy", errno, "stat", inFn);
85 copySize = fileSize = buf.st_size;
86
87// We can dispense with the copy if both files are in the same filesystem.
88// Note that the caller must have pre-allocate thed output file. We handle
89// avoiding creating a hard link to a symlink instead of the underlying file.
90//
91 if (fstat(Out.FD, &bufO)) return -OssEroute.Emsg("Copy",errno,"stat",outFn);
92 if (buf.st_dev == bufO.st_dev)
93 {char lnkBuff[1024+8]; const char *srcFn = inFn; int n;
94 if (lstat(inFn, &bufSL)) return -OssEroute.Emsg("Copy",errno,"lstat",inFn);
95 if ((bufSL.st_mode & S_IFMT) == S_IFLNK)
96 {if ((n = readlink(inFn, lnkBuff, sizeof(lnkBuff)-1)) < 0)
97 return -OssEroute.Emsg("Copy", errno, "readlink", inFn);
98 lnkBuff[n] = '\0'; srcFn = lnkBuff;
99 }
100 unlink(outFn);
101 if (link(srcFn,outFn)) return -OssEroute.Emsg("Copy",errno,"link",outFn);
102 return fileSize;
103 }
104
105// We now copy 1MB segments using direct I/O
106//
107 ioSize = (fileSize < (off_t)segSize ? fileSize : segSize);
108 while(copySize)
109 {if ((inBuff = (char *)mmap(0, ioSize, PROT_READ,
110#if defined(__FreeBSD__)
111 MAP_RESERVED0040|MAP_PRIVATE, In.FD, Offset)) == MAP_FAILED)
112#elif defined(__GNU__)
113 MAP_PRIVATE, In.FD, Offset)) == MAP_FAILED)
114#else
115 MAP_NORESERVE|MAP_PRIVATE, In.FD, Offset)) == MAP_FAILED)
116#endif
117 {OssEroute.Emsg("Copy", errno, "memory map", inFn); break;}
118 if (Write(outFn, Out.FD, inBuff, ioSize, Offset) < 0) break;
119 copySize -= ioSize; Offset += ioSize;
120 if (munmap(inBuff, ioSize) < 0)
121 {OssEroute.Emsg("Copy", errno, "unmap memory for", inFn); break;}
122 if (copySize < segSize) ioSize = copySize;
123 }
124
125// check if there was an error and if we can recover
126
127 if (copySize)
128 { if ((off_t)copySize != fileSize) return -EIO;
129 // Do a traditional copy (note that we didn't copy anything yet)
130 OssEroute.Emsg("Copy", "Trying traditional copy for", inFn, "...");
131 char ioBuff[segSize];
132 off_t rdSize, wrSize = segSize, inOff=0;
133 while(copySize)
134 {if (copySize < segSize) rdSize = wrSize = copySize;
135 else rdSize = segSize;
136 bP = ioBuff;
137 while(rdSize)
138 {do {rLen = pread(In.FD, bP, rdSize, inOff);}
139 while(rLen < 0 && errno == EINTR);
140 if (rLen <= 0) return -OssEroute.Emsg("Copy",
141 rLen ? errno : ECANCELED, "read", inFn);
142 bP += rLen; rdSize -= rLen; inOff += rLen;
143 }
144 if ((rc = Write(outFn, Out.FD, ioBuff, wrSize, Offset)) < 0) return rc;
145 copySize -= wrSize; Offset += wrSize;
146 }
147 }
148
149// Copy over any extended attributes
150//
151 if (XrdSysFAttr::Xat->Copy(inFn, In.FD, outFn, Out.FD)) return -1;
152
153// Now set the time on the file to the original time
154//
155 tBuff.actime = buf.st_atime;
156 tBuff.modtime= buf.st_mtime;
157 if (utime(outFn, &tBuff))
158 OssEroute.Emsg("Copy", errno, "set mtime for", outFn);
159
160// Success
161//
162 return fileSize;
163}
164
165/******************************************************************************/
166/* private: W r i t e */
167/******************************************************************************/
168
169int XrdOssCopy::Write(const char *outFn,
170 int oFD, char *Buff, size_t BLen, off_t BOff)
171{
172 ssize_t wLen;
173
174// Copy out a segment
175//
176 while(BLen)
177 {if ((wLen = pwrite(oFD, Buff, BLen, BOff)) < 0)
178 {if (errno == EINTR) continue;
179 else break;
180 }
181 Buff += wLen; BLen -= wLen; BOff += wLen;
182 }
183
184// Check for errors
185//
186 return (BLen ? -OssEroute.Emsg("Copy", errno, "write", outFn) : 0);
187}
XrdSysTrace OssTrace
XrdSysError OssEroute
int lstat(const char *path, struct stat *buf)
#define close(a)
Definition XrdPosix.hh:48
#define fstat(a, b)
Definition XrdPosix.hh:62
#define open
Definition XrdPosix.hh:76
#define unlink(a)
Definition XrdPosix.hh:113
#define stat(a, b)
Definition XrdPosix.hh:101
#define pwrite(a, b, c, d)
Definition XrdPosix.hh:107
#define pread(a, b, c, d)
Definition XrdPosix.hh:80
static off_t Copy(const char *inFn, const char *outFn, int outFD)
Definition XrdOssCopy.cc:59
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
static XrdSysXAttr * Xat