2 * Copyright (c) 2007, Hartmut Reuter,
3 * RZG, Max-Planck-Institut f. Plasmaphysik.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * Revised in 2010 by Chaz Chandler to enhance clientless operations.
29 * Now utilizes libafscp by Chaskiel Grundman.
30 * Work funded in part by Sine Nomine Associates (http://www.sinenomine.net/)
33 #include <afsconfig.h>
34 #include <afs/param.h>
44 #include <afs/smb_iocons.h>
46 #include <afs/cm_ioctl.h>
47 #include <afs/pioctl_nt.h>
48 #include <WINNT/syscfg.h>
51 #include <afs/afsint.h>
52 #define FSINT_COMMON_XG 1
57 #include <afs/vlserver.h>
58 #include <afs/ihandle.h>
59 #include <afs/com_err.h>
60 #include <afs/afscp.h>
68 #include <sys/malloc.h>
72 #include <hcrypto/md5.h>
73 #ifdef AFS_PTHREAD_ENV
75 pthread_key_t uclient_key;
78 static int readFile(struct cmd_syndesc *, void *);
79 static int writeFile(struct cmd_syndesc *, void *);
80 static void printDatarate(void);
81 static void summarizeDatarate(struct timeval *, const char *);
82 static int CmdProlog(struct cmd_syndesc *, char **, char **,
84 static int ScanFid(char *, struct AFSFid *);
85 static afs_int32 GetVenusFidByFid(char *, char *, int, struct afscp_venusfid **);
86 static afs_int32 GetVenusFidByPath(char *, char *, struct afscp_venusfid **);
87 static int BreakUpPath(char *, char *, char *);
89 static char pnp[AFSPATHMAX]; /* filename of this program when called */
90 static int verbose = 0; /* Set if -verbose option given */
91 static int cellGiven = 0; /* Set if -cell option given */
92 static int force = 0; /* Set if -force option given */
93 static int useFid = 0; /* Set if fidwrite/fidread/fidappend invoked */
94 static int append = 0; /* Set if append/fidappend invoked */
95 static struct timeval starttime, opentime, readtime, writetime;
96 static afs_uint64 xfered = 0;
97 static struct timeval now;
99 static int Timezone; /* Roken gettimeofday ignores the timezone */
101 static struct timezone Timezone;
104 #define BUFFLEN 65536
105 #define WRITEBUFLEN (BUFFLEN * 1024)
106 #define MEGABYTE_F 1048576.0f
109 static int md5sum = 0; /* Set if -md5 option given */
113 afs_uint32 offset; /* offset inside the buffer */
114 afs_uint32 buflen; /* total length == BUFFLEN */
115 afs_uint32 used; /* bytes used inside buffer */
120 * returns difference in seconds between two times
122 * \param[in] from start time
123 * \param[in] to end time
125 * \post returns "to" minus "from" in seconds
129 time_elapsed(struct timeval *from, struct timeval *to)
131 return (float)(to->tv_sec + (to->tv_usec * 0.000001) - from->tv_sec -
132 (from->tv_usec * 0.000001));
136 * prints current average data transfer rate at no less than 30-second intervals
141 static float oldseconds = 0.0;
142 static afs_uint64 oldxfered = 0;
145 gettimeofday(&now, &Timezone);
146 seconds = time_elapsed(&opentime, &now);
147 if ((seconds - oldseconds) > 30) {
148 fprintf(stderr, "%llu MB transferred, present data rate = %.3f MB/sec.\n", xfered >> 20, /* total bytes transferred, in MB */
149 (xfered - oldxfered) / (seconds - oldseconds) / MEGABYTE_F);
151 oldseconds = seconds;
153 } /* printDatarate */
156 * prints overall average data transfer rate and elapsed time
158 * \param[in] tvp current time (to compare with file open time)
159 * \param[in] xfer_type string identify transfer type ("read" or "write")
162 summarizeDatarate(struct timeval *tvp, const char *xfer_type)
164 float seconds = time_elapsed(&opentime, tvp);
166 fprintf(stderr, "Transfer of %llu bytes took %.3f sec.\n",
168 fprintf(stderr, "Total data rate = %.03f MB/sec. for %s\n",
169 xfered / seconds / MEGABYTE_F, xfer_type);
170 } /* summarizeDatarate */
173 * prints final MD5 sum of all file data transferred
175 * \param[in] fname file name or FID
178 summarizeMD5(char *fname)
180 afs_uint32 md5int[4];
183 MD5_Final((char *) &md5int[0], &md5);
184 p = fname + strlen(fname);
191 fprintf(stderr, "%08x%08x%08x%08x %s\n", htonl(md5int[0]),
192 htonl(md5int[1]), htonl(md5int[2]), htonl(md5int[3]), p);
196 * parses all command-line arguments
198 * \param[in] as arguments list
199 * \param[out] cellp cell name
200 * \param[out] realmp realm name
201 * \param[out] fnp filename (either fid or path)
202 * \param[out] slp "synthesized" (made up) data given
204 * \post returns 0 on success or -1 on error
208 CmdProlog(struct cmd_syndesc *as, char **cellp, char **realmp,
209 char **fnp, char **slp)
212 struct cmd_parmdesc *pdp;
215 afs_com_err(pnp, EINVAL, "(syndesc is null)");
219 /* determine which command was requested */
220 if (strncmp(as->name, "fid", 3) == 0) /* fidread/fidwrite/fidappend */
222 if ( (strcmp(as->name, "append") == 0) ||
223 (strcmp(as->name, "fidappend") == 0) )
224 append = 1; /* global */
226 /* attempts to ensure loop is bounded: */
227 for (pdp = as->parms, i = 0; pdp && (i < as->nParms); i++, pdp++) {
228 if (pdp->items != NULL) {
229 if (strcmp(pdp->name, "-verbose") == 0)
231 else if (strcmp(pdp->name, "-md5") == 0)
232 md5sum = 1; /* global */
233 else if (strcmp(pdp->name, "-cell") == 0) {
234 cellGiven = 1; /* global */
235 *cellp = pdp->items->data;
236 } else if ( (strcmp(pdp->name, "-file") == 0) ||
237 (strcmp(pdp->name, "-fid") == 0) ||
238 (strcmp(pdp->name, "-vnode") == 0) )
239 *fnp = pdp->items->data;
240 else if (strcmp(pdp->name, "-force") == 0)
241 force = 1; /* global */
242 else if (strcmp(pdp->name, "-synthesize") == 0)
243 *slp = pdp->items->data;
244 else if (strcmp(pdp->name, "-realm") == 0)
245 *realmp = pdp->items->data;
252 main(int argc, char **argv)
255 struct cmd_syndesc *ts;
256 char baseName[AFSNAMEMAX];
258 /* try to get only the base name of this executable for use in logs */
259 if (BreakUpPath(argv[0], NULL, baseName) > 0)
260 strlcpy(pnp, baseName, AFSNAMEMAX);
262 strlcpy(pnp, argv[0], AFSPATHMAX);
264 #ifdef AFS_PTHREAD_ENV
265 assert(pthread_key_create(&uclient_key, NULL) == 0);
268 ts = cmd_CreateSyntax("read", readFile, CMD_REQUIRED,
269 "read a file from AFS");
270 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
271 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
272 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
273 cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
274 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
276 ts = cmd_CreateSyntax("fidread", readFile, CMD_REQUIRED,
277 "read on a non AFS-client a file from AFS");
278 cmd_IsAdministratorCommand(ts);
279 cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
280 "volume.vnode.uniquifier");
281 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
282 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
283 cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
284 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
286 ts = cmd_CreateSyntax("write", writeFile, CMD_REQUIRED,
287 "write a file into AFS");
288 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
289 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
290 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
291 cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
292 cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
293 "overwrite existing file");
294 cmd_AddParm(ts, "-synthesize", CMD_SINGLE, CMD_OPTIONAL,
295 "create data pattern of specified length instead reading from stdin");
296 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
298 ts = cmd_CreateSyntax("fidwrite", writeFile, CMD_REQUIRED,
299 "write a file into AFS");
300 cmd_IsAdministratorCommand(ts);
301 cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED,
302 "volume.vnode.uniquifier");
303 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
304 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
305 cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
306 cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
307 "overwrite existing file");
308 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
310 ts = cmd_CreateSyntax("append", writeFile, CMD_REQUIRED,
311 "append to a file in AFS");
312 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
313 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
314 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
315 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
317 ts = cmd_CreateSyntax("fidappend", writeFile, CMD_REQUIRED,
318 "append to a file in AFS");
319 cmd_IsAdministratorCommand(ts);
320 cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED,
321 "volume.vnode.uniquifier");
322 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
323 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
324 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
326 if (afscp_Init(NULL) != 0)
329 code = cmd_Dispatch(argc, argv);
336 * standardized way of parsing a File ID (FID) from command line input
338 * \param[in] fidString dot-delimited FID triple
339 * \param[out] fid pointer to the AFSFid to fill in
341 * \post The FID pointed to by "fid" is filled in which the parsed Volume,
342 * Vnode, and Uniquifier data. The string should be in the format
343 * of three numbers separated by dot (.) delimiters, representing
344 * (in order) the volume id, vnode number, and uniquifier.
345 * Example: "576821346.1.1"
348 ScanFid(char *fidString, struct AFSFid *fid)
351 long unsigned int f1, f2, f3;
354 i = sscanf(fidString, "%lu.%lu.%lu", &f1, &f2, &f3);
355 fid->Volume = (afs_uint32) f1;
356 fid->Vnode = (afs_uint32) f2;
357 fid->Unique = (afs_uint32) f3;
364 afs_com_err(pnp, code, "(invalid FID triple: %s)", fidString);
371 * look up cell info and verify FID info from user input
373 * \param[in] fidString string containing FID info
374 * \param[in] cellName cell name string
375 * \param[in] onlyRW bool: 1 = RW vol only, 0 = any vol type
376 * \param[out] avfpp pointer to venusfid info
378 * \post *avfpp will contain the VenusFid info found for the FID
379 * given by the used in the string fidString and zero is
380 * returned. If not found, an appropriate afs error code
381 * is returned and *avfpp will be NULL.
383 * \note Any non-NULL avfpp returned should later be freed with
384 * afscp_FreeFid() when no longer needed.
387 GetVenusFidByFid(char *fidString, char *cellName, int onlyRW,
388 struct afscp_venusfid **avfpp)
392 struct afscp_volume *avolp;
394 if (*avfpp == NULL) {
395 *avfpp = malloc(sizeof(struct afscp_venusfid));
396 if ( *avfpp == NULL ) {
401 memset(*avfpp, 0, sizeof(struct afscp_venusfid));
403 if (cellName == NULL) {
404 (*avfpp)->cell = afscp_DefaultCell();
406 (*avfpp)->cell = afscp_CellByName(cellName, NULL);
408 if ((*avfpp)->cell == NULL) {
409 if (afscp_errno == 0)
416 code = ScanFid(fidString, &((*avfpp)->fid));
422 avolp = afscp_VolumeById((*avfpp)->cell, (*avfpp)->fid.Volume);
424 if (afscp_errno == 0)
428 afs_com_err(pnp, code, "(finding volume %lu)",
429 afs_printable_uint32_lu((*avfpp)->fid.Volume));
433 if ( onlyRW && (avolp->voltype != RWVOL) ) {
434 avolp = afscp_VolumeByName((*avfpp)->cell, avolp->name, RWVOL);
436 if (afscp_errno == 0)
440 afs_com_err(pnp, code, "(finding volume %lu)",
441 afs_printable_uint32_lu((*avfpp)->fid.Volume));
444 (*avfpp)->fid.Volume = avolp->id; /* is this safe? */
447 code = afscp_Stat((*avfpp), &sbuf);
449 afs_com_err(pnp, code, "(stat failed with code %d)", code);
453 } /* GetVenusFidByFid */
456 * Split a full path up into dirName and baseName components
458 * \param[in] fullPath can be absolute, relative, or local
459 * \param[out] dirName pointer to allocated char buffer or NULL
460 * \param[out] baseName pointer to allocated char buffer or NULL
462 * \post To the fulleset extent possible, the rightmost full path
463 * component will be copied into baseName and all other
464 * components into dirName (minus the trailing path separator).
465 * If either dirName or baseName are NULL, only the non-NULL
466 * pointer will be filled in (but both can't be null or it would
467 * be pointless) -- so the caller can retrieve, say, only baseName
468 * if desired. The return code is the number of strings copied:
469 * 0 if neither dirName nor baseName could be filled in
470 * 1 if either dirName or baseName were filled in
471 * 2 if both dirName and baseName were filled in
474 BreakUpPath(char *fullPath, char *dirName, char *baseName)
477 size_t dirNameLen = 0;
478 int code = 0, useDirName = 1, useBaseName = 1;
480 if (fullPath == NULL) {
486 if (baseName == NULL)
488 if (!useBaseName && !useDirName) {
489 /* would be pointless to continue -- must be error in call */
493 lastSlash = strrchr(fullPath, '\\');
495 lastSlash = strrchr(fullPath, '/');
497 if (lastSlash != NULL) {
498 /* then lastSlash points to the last path separator in fullPath */
500 dirNameLen = strlen(fullPath) - strlen(lastSlash);
501 strlcpy(dirName, fullPath, dirNameLen + 1);
506 strlcpy(baseName, lastSlash, strlen(lastSlash) + 1);
510 /* there are no path separators in fullPath -- it's just a baseName */
512 strlcpy(baseName, fullPath, strlen(fullPath) + 1);
520 * Get the VenusFid info available for the file at AFS path 'fullPath'.
521 * Works without pioctls/afsd by using libafscp. Analogous to
522 * get_file_cell() in the previous iteration of afsio.
524 * \param[in] fullPath the file name
525 * \param[in] cellName the cell name to look up
526 * \param[out] avfpp pointer to Venus FID info to be filled in
528 * \post If the path resolves successfully (using afscp_ResolvePath),
529 * then vfpp will contain the Venus FID info (cell info plus
530 * AFSFid) of the last path segment in fullPath.
533 GetVenusFidByPath(char *fullPath, char *cellName,
534 struct afscp_venusfid **avfpp)
538 if (fullPath == NULL) {
542 if (cellName != NULL) {
543 code = (afs_int32) afscp_SetDefaultCell(cellName);
549 *avfpp = afscp_ResolvePath(fullPath);
550 if (*avfpp == NULL) {
551 if (afscp_errno == 0)
558 } /* GetVenusFidByPath */
561 readFile(struct cmd_syndesc *as, void *unused)
567 struct AFSFetchStatus OutStatus;
568 struct afscp_venusfid *avfp = NULL;
571 afs_int64 length = 0, Len;
576 int bufflen = BUFFLEN;
579 /* stdout on Windows defaults to _O_TEXT mode */
580 _setmode(1, _O_BINARY);
583 gettimeofday(&starttime, &Timezone);
585 CmdProlog(as, &cell, &realm, &fname, NULL);
586 afscp_AnonymousAuth(1);
592 code = afscp_SetDefaultRealm(realm);
595 code = afscp_SetDefaultCell(cell);
598 code = GetVenusFidByFid(fname, cell, 0, &avfp);
600 code = GetVenusFidByPath(fname, cell, &avfp);
602 afs_com_err(pnp, code, "(file not found: %s)", fname);
606 if (avfp->fid.Vnode & 1) {
608 afs_com_err(pnp, code, "(%s is a directory, not a file)", fname);
613 code = afscp_GetStatus(avfp, &OutStatus);
615 afs_inet_ntoa_r(avfp->cell->fsservers[0]->addrs[0], ipv4_addr);
616 afs_com_err(pnp, code, "(failed to get status of file %s from"
617 "server %s, code = %d)", fname, ipv4_addr, code);
622 gettimeofday(&opentime, &Timezone);
624 fprintf(stderr, "Startup to find the file took %.3f sec.\n",
625 time_elapsed(&starttime, &opentime));
626 Len = OutStatus.Length_hi;
628 Len += OutStatus.Length;
630 buf = (char *) malloc(bufflen * sizeof(char));
633 afs_com_err(pnp, code, "(cannot allocate buffer)");
637 memset(buf, 0, bufflen * sizeof(char));
639 while (!code && NonZeroInt64(length)) {
640 if (length > bufflen)
643 len = (afs_int32) length;
644 bytes = afscp_PRead(avfp, buf, len, Pos);
646 code = -3; /* what error name should we use here? */
648 MD5_Update(&md5, buf, len);
650 len = write(1, buf, len); /* to stdout */
663 gettimeofday(&readtime, &Timezone);
667 summarizeDatarate(&readtime, "read");
675 writeFile(struct cmd_syndesc *as, void *unused)
679 char *sSynthLen = NULL;
682 afs_int32 byteswritten;
683 struct AFSFetchStatus OutStatus;
684 struct AFSStoreStatus InStatus;
685 struct afscp_venusfid *dirvfp = NULL, *newvfp = NULL;
687 afs_int64 length, Len, synthlength = 0, offset = 0;
692 struct wbuf *bufchain = 0;
693 struct wbuf *previous, *tbuf;
694 char dirName[AFSPATHMAX];
695 char baseName[AFSNAMEMAX];
699 /* stdin on Windows defaults to _O_TEXT mode */
700 _setmode(0, _O_BINARY);
703 CmdProlog(as, &cell, &realm, &fname, &sSynthLen);
704 afscp_AnonymousAuth(1);
707 code = afscp_SetDefaultRealm(realm);
710 code = afscp_SetDefaultCell(cell);
713 code = util_GetInt64(sSynthLen, &synthlength);
715 afs_com_err(pnp, code, "(invalid value for synthesize length %s)",
723 code = GetVenusFidByFid(fname, cell, 1, &newvfp);
725 afs_com_err(pnp, code, "(GetVenusFidByFid returned code %d)", code);
729 code = GetVenusFidByPath(fname, cell, &newvfp);
730 if (code == 0) { /* file was found */
735 * file cannot already exist if specified by path and not
736 * appending to it unless user forces overwrite
739 afscp_FreeFid(newvfp);
740 afs_com_err(pnp, code, "(use -force to overwrite)");
743 } else { /* file not found */
746 afs_com_err(pnp, code, "(cannot append to non-existent file)");
750 if (!append && !overWrite) { /* must create a new file in this case */
751 if ( BreakUpPath(fname, dirName, baseName) != 2 ) {
753 afs_com_err(pnp, code, "(must provide full AFS path)");
754 afscp_FreeFid(newvfp);
758 code = GetVenusFidByPath(dirName, cell, &dirvfp);
759 afscp_FreeFid(newvfp); /* release now-unneeded fid */
762 afs_com_err(pnp, code, "(is dir %s in AFS?)", dirName);
768 if ( (newvfp != NULL) && (newvfp->fid.Vnode & 1) ) {
770 afs_com_err(pnp, code, "(%s is a directory, not a file)", fname);
771 afscp_FreeFid(newvfp);
772 afscp_FreeFid(dirvfp);
775 gettimeofday(&starttime, &Timezone);
777 InStatus.UnixModeBits = 0644;
778 if (newvfp == NULL) {
779 code = afscp_CreateFile(dirvfp, baseName, &InStatus, &newvfp);
781 afs_com_err(pnp, code,
782 "(could not create file %s in directory %lu.%lu.%lu)",
783 baseName, afs_printable_uint32_lu(dirvfp->fid.Volume),
784 afs_printable_uint32_lu(dirvfp->fid.Vnode),
785 afs_printable_uint32_lu(dirvfp->fid.Unique));
789 code = afscp_GetStatus(newvfp, &OutStatus);
791 afs_inet_ntoa_r(newvfp->cell->fsservers[0]->addrs[0], ipv4_addr);
792 afs_com_err(pnp, code, "(failed to get status of file %s from"
793 "server %s, code = %d)", fname, ipv4_addr, code);
794 afscp_FreeFid(newvfp);
795 afscp_FreeFid(dirvfp);
799 if ( !append && !force &&
800 (OutStatus.Length != 0 || OutStatus.Length_hi !=0 ) ) {
802 * file exists, is of non-zero length, and we're not appending
803 * to it: user must force overwrite
804 * (covers fidwrite edge case)
807 afscp_FreeFid(newvfp);
808 afscp_FreeFid(dirvfp);
809 afs_com_err(pnp, code, "(use -force to overwrite)");
813 InStatus.Mask = AFS_SETMODE + AFS_FSYNC;
815 Pos = OutStatus.Length_hi;
816 Pos = (Pos << 32) | OutStatus.Length;
819 previous = (struct wbuf *)&bufchain;
824 * currently, these two while loops (1) read the whole source file in
825 * before (2) writing any of it out, meaning that afsio can't deal with
826 * files larger than the maximum amount of memory designated for
827 * reading a file in (WRITEBUFLEN).
828 * Consider going to a single loop, like in readFile(), though will
829 * have implications on timing statistics (such as the "Startup to
830 * find the file" time, below).
833 while (Len < WRITEBUFLEN) {
834 tbuf = (struct wbuf *)malloc(sizeof(struct wbuf));
838 afscp_FreeFid(newvfp);
839 afscp_FreeFid(dirvfp);
840 afs_com_err(pnp, code, "(cannot allocate buffer)");
845 memset(tbuf, 0, sizeof(struct wbuf));
846 tbuf->buflen = BUFFLEN;
848 afs_int64 ll, l = tbuf->buflen;
851 for (ll = 0; ll < l; ll += 4096) {
852 sprintf(&tbuf->buf[ll], "Offset (0x%x, 0x%x)\n",
853 (unsigned int)((offset + ll) >> 32),
854 (unsigned int)((offset + ll) & 0xffffffff));
858 tbuf->used = (afs_int32) l;
860 tbuf->used = read(0, &tbuf->buf, tbuf->buflen); /* from stdin */
861 if (tbuf->used == 0) {
866 MD5_Update(&md5, &tbuf->buf, tbuf->used);
867 previous->next = tbuf;
871 gettimeofday(&opentime, &Timezone);
873 fprintf(stderr, "Startup to find the file took %.3f sec.\n",
874 time_elapsed(&starttime, &opentime));
876 while (!code && bytes) {
881 for (tbuf = bufchain; tbuf; tbuf = tbuf->next) {
884 byteswritten = afscp_PWrite(newvfp, tbuf->buf,
885 tbuf->used, Pos + xfered);
886 if (byteswritten != tbuf->used) {
887 fprintf(stderr,"Only %d instead of %" AFS_INT64_FMT " bytes transferred by rx_Write()\n", byteswritten, length);
888 fprintf(stderr, "At %" AFS_UINT64_FMT " bytes from the end\n", length);
892 xfered += tbuf->used;
895 length -= tbuf->used;
901 for (tbuf = bufchain; tbuf; tbuf = tbuf->next) {
904 afs_int64 ll, l = tbuf->buflen;
907 for (ll = 0; ll < l; ll += 4096) {
908 sprintf(&tbuf->buf[ll], "Offset (0x%x, 0x%x)\n",
909 (unsigned int)((offset + ll) >> 32),
910 (unsigned int)((offset + ll) & 0xffffffff));
914 tbuf->used = (afs_int32) l;
916 tbuf->used = read(0, &tbuf->buf, tbuf->buflen); /* from stdin */
920 MD5_Update(&md5, &tbuf->buf, tbuf->used);
926 afscp_FreeFid(newvfp);
927 afscp_FreeFid(dirvfp);
929 gettimeofday(&writetime, &Timezone);
931 afs_com_err(pnp, code, "(%s failed with code %d)", as->name,
933 } else if (verbose) {
934 summarizeDatarate(&writetime, "write");
938 bufchain = tbuf->next;