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>
42 #include <afs/smb_iocons.h>
44 #include <afs/cm_ioctl.h>
45 #include <afs/pioctl_nt.h>
46 #include <WINNT/syscfg.h>
48 #include <afs/afsint.h>
49 #define FSINT_COMMON_XG 1
55 #include <afs/vlserver.h>
56 #include <afs/ihandle.h>
57 #include <afs/com_err.h>
58 #include <afs/afscp.h>
63 #include <hcrypto/md5.h>
64 #ifdef AFS_PTHREAD_ENV
65 pthread_key_t uclient_key;
68 static int lockFile(struct cmd_syndesc *, void *);
69 static int readFile(struct cmd_syndesc *, void *);
70 static int writeFile(struct cmd_syndesc *, void *);
71 static void printDatarate(void);
72 static void summarizeDatarate(struct timeval *, const char *);
73 static int CmdProlog(struct cmd_syndesc *, char **, char **,
75 static int ScanFid(char *, struct AFSFid *);
76 static afs_int32 GetVenusFidByFid(char *, char *, int, struct afscp_venusfid **);
77 static afs_int32 GetVenusFidByPath(char *, char *, struct afscp_venusfid **);
78 static int BreakUpPath(char *, char *, char *, size_t);
80 static char pnp[AFSPATHMAX]; /* filename of this program when called */
81 static int verbose = 0; /* Set if -verbose option given */
82 static int clear = 0; /* Set if -clear option given,
83 Unset if -crypt given; default is -crypt */
84 static int cellGiven = 0; /* Set if -cell option given */
85 static int force = 0; /* Set if -force option given */
86 static int readlock = 0; /* Set if -readlock option given */
87 static int waittime = 0; /* Set if -waittime option given */
88 static int useFid = 0; /* Set if fidwrite/fidread/fidappend invoked */
89 static int append = 0; /* Set if append/fidappend invoked */
90 static struct timeval starttime, opentime, readtime, writetime;
91 static afs_uint64 xfered = 0;
92 static struct timeval now;
94 static int Timezone; /* Roken gettimeofday ignores the timezone */
96 static struct timezone Timezone;
100 #define WRITEBUFLEN (BUFFLEN * 1024)
101 #define MEGABYTE_F 1048576.0f
104 static int md5sum = 0; /* Set if -md5 option given */
108 afs_uint32 offset; /* offset inside the buffer */
109 afs_uint32 buflen; /* total length == BUFFLEN */
110 afs_uint32 used; /* bytes used inside buffer */
115 * returns difference in seconds between two times
117 * \param[in] from start time
118 * \param[in] to end time
120 * \post returns "to" minus "from" in seconds
124 time_elapsed(struct timeval *from, struct timeval *to)
126 return (float)(to->tv_sec + (to->tv_usec * 0.000001) - from->tv_sec -
127 (from->tv_usec * 0.000001));
131 * prints current average data transfer rate at no less than 30-second intervals
136 static float oldseconds = 0.0;
137 static afs_uint64 oldxfered = 0;
140 gettimeofday(&now, &Timezone);
141 seconds = time_elapsed(&opentime, &now);
142 if ((seconds - oldseconds) > 30) {
143 fprintf(stderr, "%llu MB transferred, present data rate = %.3f MB/sec.\n", xfered >> 20, /* total bytes transferred, in MB */
144 (xfered - oldxfered) / (seconds - oldseconds) / MEGABYTE_F);
146 oldseconds = seconds;
148 } /* printDatarate */
151 * prints overall average data transfer rate and elapsed time
153 * \param[in] tvp current time (to compare with file open time)
154 * \param[in] xfer_type string identify transfer type ("read" or "write")
157 summarizeDatarate(struct timeval *tvp, const char *xfer_type)
159 float seconds = time_elapsed(&opentime, tvp);
161 fprintf(stderr, "Transfer of %llu bytes took %.3f sec.\n",
163 fprintf(stderr, "Total data rate = %.03f MB/sec. for %s\n",
164 xfered / seconds / MEGABYTE_F, xfer_type);
165 } /* summarizeDatarate */
168 * prints final MD5 sum of all file data transferred
170 * \param[in] fname file name or FID
173 summarizeMD5(char *fname)
175 afs_uint32 md5int[4];
178 MD5_Final((char *) &md5int[0], &md5);
179 p = fname + strlen(fname);
186 fprintf(stderr, "%08x%08x%08x%08x %s\n", htonl(md5int[0]),
187 htonl(md5int[1]), htonl(md5int[2]), htonl(md5int[3]), p);
192 ConvertAFSPath(char **fnp)
196 for (p = *fnp; *p; p++) {
202 if (p[0] == '/' && p[1] == '/')
205 #endif /* AFS_NT40_ENV */
208 * parses all command-line arguments
210 * \param[in] as arguments list
211 * \param[out] cellp cell name
212 * \param[out] realmp realm name
213 * \param[out] fnp filename (either fid or path)
214 * \param[out] slp "synthesized" (made up) data given
216 * \post returns 0 on success or -1 on error
220 CmdProlog(struct cmd_syndesc *as, char **cellp, char **realmp,
221 char **fnp, char **slp)
224 struct cmd_parmdesc *pdp;
227 afs_com_err(pnp, EINVAL, "(syndesc is null)");
231 /* determine which command was requested */
232 if (strncmp(as->name, "fid", 3) == 0) /* fidread/fidwrite/fidappend */
234 if ( (strcmp(as->name, "append") == 0) ||
235 (strcmp(as->name, "fidappend") == 0) )
236 append = 1; /* global */
238 /* attempts to ensure loop is bounded: */
239 for (pdp = as->parms, i = 0; pdp && (i < as->nParms); i++, pdp++) {
240 if (pdp->items != NULL) {
241 if (strcmp(pdp->name, "-verbose") == 0)
243 if (strcmp(pdp->name, "-clear") == 0)
245 if (strcmp(pdp->name, "-crypt") == 0)
247 else if (strcmp(pdp->name, "-md5") == 0)
248 md5sum = 1; /* global */
249 else if (strcmp(pdp->name, "-cell") == 0) {
250 cellGiven = 1; /* global */
251 *cellp = pdp->items->data;
252 } else if ( strcmp(pdp->name, "-file") == 0) {
253 *fnp = pdp->items->data;
256 #endif /* AFS_NT40_ENV */
257 } else if ( (strcmp(pdp->name, "-fid") == 0) ||
258 (strcmp(pdp->name, "-vnode") == 0) ) {
259 *fnp = pdp->items->data;
260 } else if (strcmp(pdp->name, "-force") == 0)
261 force = 1; /* global */
262 else if (strcmp(pdp->name, "-synthesize") == 0)
263 *slp = pdp->items->data;
264 else if (strcmp(pdp->name, "-realm") == 0)
265 *realmp = pdp->items->data;
266 else if (strcmp(pdp->name, "-wait") == 0)
267 waittime = atoi(pdp->items->data);
268 else if (strcmp(pdp->name, "-readlock") == 0)
276 main(int argc, char **argv)
278 struct cmd_syndesc *ts;
279 char baseName[AFSNAMEMAX];
282 /* try to get only the base name of this executable for use in logs */
284 char *p = strdup(argv[0]);
286 code = BreakUpPath(p, NULL, baseName, AFSNAMEMAX);
289 code = BreakUpPath(argv[0], NULL, baseName, AFSNAMEMAX);
292 strlcpy(pnp, baseName, AFSNAMEMAX);
294 strlcpy(pnp, argv[0], AFSPATHMAX);
296 #ifdef AFS_PTHREAD_ENV
297 opr_Verify(pthread_key_create(&uclient_key, NULL) == 0);
300 ts = cmd_CreateSyntax("lock", lockFile, (void *)LockWrite,
301 "lock a file in AFS");
302 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
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, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
306 cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
308 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
309 cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
310 cmd_AddParm(ts, "-readlock", CMD_FLAG, CMD_OPTIONAL, "read lock only");
312 ts = cmd_CreateSyntax("fidlock", lockFile, (void *)LockWrite,
313 "lock by FID a file from AFS");
314 cmd_IsAdministratorCommand(ts);
315 cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
316 "volume.vnode.uniquifier");
317 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
318 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
319 cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
320 cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
322 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
323 cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
324 cmd_AddParm(ts, "-readlock", CMD_FLAG, CMD_OPTIONAL, "read lock only");
326 ts = cmd_CreateSyntax("unlock", lockFile, (void *)LockRelease,
327 "unlock a file in AFS");
328 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
329 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
330 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
331 cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
332 cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
334 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
335 cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
337 ts = cmd_CreateSyntax("fidunlock", lockFile, (void *)LockRelease,
338 "unlock by FID a file from AFS");
339 cmd_IsAdministratorCommand(ts);
340 cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
341 "volume.vnode.uniquifier");
342 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
343 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
344 cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
345 cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
347 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
348 cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
350 ts = cmd_CreateSyntax("read", readFile, NULL,
351 "read a file from AFS");
352 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
353 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
354 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
355 cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
356 cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
357 cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
358 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
360 ts = cmd_CreateSyntax("fidread", readFile, CMD_REQUIRED,
361 "read on a non AFS-client a file from AFS");
362 cmd_IsAdministratorCommand(ts);
363 cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
364 "volume.vnode.uniquifier");
365 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
366 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
367 cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
368 cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
369 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
371 ts = cmd_CreateSyntax("write", writeFile, NULL,
372 "write a file into AFS");
373 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
374 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
375 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
376 cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
377 cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
378 cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
379 cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
380 "overwrite existing file");
381 cmd_AddParm(ts, "-synthesize", CMD_SINGLE, CMD_OPTIONAL,
382 "create data pattern of specified length instead reading from stdin");
383 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
385 ts = cmd_CreateSyntax("fidwrite", writeFile, CMD_REQUIRED,
386 "write a file into AFS");
387 cmd_IsAdministratorCommand(ts);
388 cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED,
389 "volume.vnode.uniquifier");
390 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
391 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
392 cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
393 cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
394 cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
395 cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
396 "overwrite existing file");
397 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
399 ts = cmd_CreateSyntax("append", writeFile, NULL,
400 "append to a file in AFS");
401 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
402 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
403 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
404 cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
405 cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
406 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
408 ts = cmd_CreateSyntax("fidappend", writeFile, NULL,
409 "append to a file in AFS");
410 cmd_IsAdministratorCommand(ts);
411 cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED,
412 "volume.vnode.uniquifier");
413 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
414 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
415 cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
416 cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
417 cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
419 if (afscp_Init(NULL) != 0)
422 cmd_Dispatch(argc, argv);
429 * standardized way of parsing a File ID (FID) from command line input
431 * \param[in] fidString dot-delimited FID triple
432 * \param[out] fid pointer to the AFSFid to fill in
434 * \post The FID pointed to by "fid" is filled in which the parsed Volume,
435 * Vnode, and Uniquifier data. The string should be in the format
436 * of three numbers separated by dot (.) delimiters, representing
437 * (in order) the volume id, vnode number, and uniquifier.
438 * Example: "576821346.1.1"
441 ScanFid(char *fidString, struct AFSFid *fid)
444 long unsigned int f1, f2, f3;
447 i = sscanf(fidString, "%lu.%lu.%lu", &f1, &f2, &f3);
448 fid->Volume = (afs_uint32) f1;
449 fid->Vnode = (afs_uint32) f2;
450 fid->Unique = (afs_uint32) f3;
457 afs_com_err(pnp, code, "(invalid FID triple: %s)", fidString);
464 * look up cell info and verify FID info from user input
466 * \param[in] fidString string containing FID info
467 * \param[in] cellName cell name string
468 * \param[in] onlyRW bool: 1 = RW vol only, 0 = any vol type
469 * \param[out] avfpp pointer to venusfid info
471 * \post *avfpp will contain the VenusFid info found for the FID
472 * given by the used in the string fidString and zero is
473 * returned. If not found, an appropriate afs error code
474 * is returned and *avfpp will be NULL.
476 * \note Any non-NULL avfpp returned should later be freed with
477 * afscp_FreeFid() when no longer needed.
480 GetVenusFidByFid(char *fidString, char *cellName, int onlyRW,
481 struct afscp_venusfid **avfpp)
485 struct afscp_volume *avolp;
487 if (*avfpp == NULL) {
488 *avfpp = calloc(1, sizeof(struct afscp_venusfid));
489 if ( *avfpp == NULL ) {
495 if (cellName == NULL) {
496 (*avfpp)->cell = afscp_DefaultCell();
498 (*avfpp)->cell = afscp_CellByName(cellName, NULL);
500 if ((*avfpp)->cell == NULL) {
501 if (afscp_errno == 0)
508 code = ScanFid(fidString, &((*avfpp)->fid));
514 avolp = afscp_VolumeById((*avfpp)->cell, (*avfpp)->fid.Volume);
516 if (afscp_errno == 0)
520 afs_com_err(pnp, code, "(finding volume %lu)",
521 afs_printable_uint32_lu((*avfpp)->fid.Volume));
525 if ( onlyRW && (avolp->voltype != RWVOL) ) {
526 avolp = afscp_VolumeByName((*avfpp)->cell, avolp->name, RWVOL);
528 if (afscp_errno == 0)
532 afs_com_err(pnp, code, "(finding volume %lu)",
533 afs_printable_uint32_lu((*avfpp)->fid.Volume));
536 (*avfpp)->fid.Volume = avolp->id; /* is this safe? */
539 code = afscp_Stat((*avfpp), &sbuf);
541 afs_com_err(pnp, code, "(stat failed with code %d)", code);
545 } /* GetVenusFidByFid */
548 * Split a full path up into dirName and baseName components
550 * \param[in] fullPath can be absolute, relative, or local
551 * \param[out] dirName pointer to allocated char buffer or NULL
552 * \param[out] baseName pointer to allocated char buffer or NULL
554 * \post To the fulleset extent possible, the rightmost full path
555 * component will be copied into baseName and all other
556 * components into dirName (minus the trailing path separator).
557 * If either dirName or baseName are NULL, only the non-NULL
558 * pointer will be filled in (but both can't be null or it would
559 * be pointless) -- so the caller can retrieve, say, only baseName
560 * if desired. The return code is the number of strings copied:
561 * 0 if neither dirName nor baseName could be filled in
562 * 1 if either dirName or baseName were filled in
563 * 2 if both dirName and baseName were filled in
566 BreakUpPath(char *fullPath, char *dirName, char *baseName, size_t baseNameSize)
569 size_t dirNameLen = 0;
570 int code = 0, useDirName = 1, useBaseName = 1;
572 if (fullPath == NULL) {
578 if (baseName == NULL)
580 if (!useBaseName && !useDirName) {
581 /* would be pointless to continue -- must be error in call */
584 lastSlash = strrchr(fullPath, '/');
585 if (lastSlash != NULL) {
586 /* then lastSlash points to the last path separator in fullPath */
588 dirNameLen = strlen(fullPath) - strlen(lastSlash);
589 strlcpy(dirName, fullPath, min(dirNameLen + 1, baseNameSize));
594 strlcpy(baseName, lastSlash, min(strlen(lastSlash) + 1, baseNameSize));
598 /* there are no path separators in fullPath -- it's just a baseName */
600 strlcpy(baseName, fullPath, min(strlen(fullPath) + 1, baseNameSize));
608 * Get the VenusFid info available for the file at AFS path 'fullPath'.
609 * Works without pioctls/afsd by using libafscp. Analogous to
610 * get_file_cell() in the previous iteration of afsio.
612 * \param[in] fullPath the file name
613 * \param[in] cellName the cell name to look up
614 * \param[out] avfpp pointer to Venus FID info to be filled in
616 * \post If the path resolves successfully (using afscp_ResolvePath),
617 * then vfpp will contain the Venus FID info (cell info plus
618 * AFSFid) of the last path segment in fullPath.
621 GetVenusFidByPath(char *fullPath, char *cellName,
622 struct afscp_venusfid **avfpp)
626 if (fullPath == NULL) {
630 if (cellName != NULL) {
631 code = (afs_int32) afscp_SetDefaultCell(cellName);
637 *avfpp = afscp_ResolvePath(fullPath);
638 if (*avfpp == NULL) {
639 if (afscp_errno == 0)
646 } /* GetVenusFidByPath */
649 lockFile(struct cmd_syndesc *as, void *arock)
655 struct AFSFetchStatus OutStatus;
656 struct afscp_venusfid *avfp = NULL;
659 int locktype = (int)(intptr_t) arock;
662 /* stdout on Windows defaults to _O_TEXT mode */
663 _setmode(1, _O_BINARY);
666 gettimeofday(&starttime, &Timezone);
668 CmdProlog(as, &cell, &realm, &fname, NULL);
669 afscp_AnonymousAuth(1);
673 if ((locktype == LockWrite) && readlock)
677 afscp_SetDefaultRealm(realm);
680 afscp_SetDefaultCell(cell);
683 code = GetVenusFidByFid(fname, cell, 0, &avfp);
685 code = GetVenusFidByPath(fname, cell, &avfp);
687 afs_com_err(pnp, code, "(file not found: %s)", fname);
693 code = afscp_GetStatus(avfp, &OutStatus);
695 afs_inet_ntoa_r(avfp->cell->fsservers[0]->addrs[0], ipv4_addr);
696 afs_com_err(pnp, code, "(failed to get status of file %s from"
697 "server %s, code = %d)", fname, ipv4_addr, code);
702 if (locktype != LockRelease) {
703 while (OutStatus.lockCount != 0) {
704 code = afscp_WaitForCallback(avfp, waittime);
705 if ((code == -1) && (afscp_errno == ETIMEDOUT))
707 if ((code = afscp_GetStatus(avfp, &OutStatus)) != 0)
711 if (OutStatus.lockCount == 0) {
717 code = afscp_Lock(avfp, locktype);
718 if ((code == -1) && (afscp_errno == EWOULDBLOCK))
727 afs_com_err(pnp, code, "(failed to change lock status: %d)", afscp_errno);
733 readFile(struct cmd_syndesc *as, void *unused)
739 struct AFSFetchStatus OutStatus;
740 struct afscp_venusfid *avfp = NULL;
743 afs_int64 length = 0, Len;
748 int bufflen = BUFFLEN;
751 /* stdout on Windows defaults to _O_TEXT mode */
752 _setmode(1, _O_BINARY);
755 gettimeofday(&starttime, &Timezone);
757 CmdProlog(as, &cell, &realm, &fname, NULL);
758 afscp_AnonymousAuth(1);
766 afscp_SetDefaultRealm(realm);
769 afscp_SetDefaultCell(cell);
772 code = GetVenusFidByFid(fname, cell, 0, &avfp);
774 code = GetVenusFidByPath(fname, cell, &avfp);
777 afs_com_err(pnp, code, "(file not found: %s)", fname);
781 if (avfp->fid.Vnode & 1) {
783 afs_com_err(pnp, code, "(%s is a directory, not a file)", fname);
788 code = afscp_GetStatus(avfp, &OutStatus);
790 afs_inet_ntoa_r(avfp->cell->fsservers[0]->addrs[0], ipv4_addr);
791 afs_com_err(pnp, code, "(failed to get status of file %s from"
792 "server %s, code = %d)", fname, ipv4_addr, code);
797 gettimeofday(&opentime, &Timezone);
799 fprintf(stderr, "Startup to find the file took %.3f sec.\n",
800 time_elapsed(&starttime, &opentime));
801 Len = OutStatus.Length_hi;
803 Len += OutStatus.Length;
805 buf = calloc(bufflen, sizeof(char));
808 afs_com_err(pnp, code, "(cannot allocate buffer)");
813 while (!code && NonZeroInt64(length)) {
814 if (length > bufflen)
817 len = (afs_int32) length;
818 bytes = afscp_PRead(avfp, buf, len, Pos);
820 code = -3; /* what error name should we use here? */
822 MD5_Update(&md5, buf, len);
824 len = write(1, buf, len); /* to stdout */
837 gettimeofday(&readtime, &Timezone);
841 summarizeDatarate(&readtime, "read");
849 writeFile(struct cmd_syndesc *as, void *unused)
853 char *sSynthLen = NULL;
856 afs_int32 byteswritten;
857 struct AFSFetchStatus OutStatus;
858 struct AFSStoreStatus InStatus;
859 struct afscp_venusfid *dirvfp = NULL, *newvfp = NULL;
861 afs_int64 length, Len, synthlength = 0, offset = 0;
866 struct wbuf *bufchain = 0;
867 struct wbuf *previous, *tbuf;
868 char dirName[AFSPATHMAX];
869 char baseName[AFSNAMEMAX];
873 /* stdin on Windows defaults to _O_TEXT mode */
874 _setmode(0, _O_BINARY);
877 CmdProlog(as, &cell, &realm, &fname, &sSynthLen);
878 afscp_AnonymousAuth(1);
883 afscp_SetDefaultRealm(realm);
886 afscp_SetDefaultCell(cell);
889 code = util_GetInt64(sSynthLen, &synthlength);
891 afs_com_err(pnp, code, "(invalid value for synthesize length %s)",
899 code = GetVenusFidByFid(fname, cell, 1, &newvfp);
901 afscp_FreeFid(newvfp);
902 afs_com_err(pnp, code, "(GetVenusFidByFid returned code %d)", code);
906 code = GetVenusFidByPath(fname, cell, &newvfp);
907 if (code == 0) { /* file was found */
912 * file cannot already exist if specified by path and not
913 * appending to it unless user forces overwrite
916 afscp_FreeFid(newvfp);
917 afs_com_err(pnp, code, "(use -force to overwrite)");
920 } else { /* file not found */
923 afs_com_err(pnp, code, "(cannot append to non-existent file)");
927 if (!append && !overWrite) { /* must create a new file in this case */
928 if ( BreakUpPath(fname, dirName, baseName, AFSNAMEMAX) != 2 ) {
930 afs_com_err(pnp, code, "(must provide full AFS path)");
931 afscp_FreeFid(newvfp);
935 code = GetVenusFidByPath(dirName, cell, &dirvfp);
936 afscp_FreeFid(newvfp); /* release now-unneeded fid */
939 afs_com_err(pnp, code, "(is dir %s in AFS?)", dirName);
945 if ( (newvfp != NULL) && (newvfp->fid.Vnode & 1) ) {
947 afs_com_err(pnp, code, "(%s is a directory, not a file)", fname);
948 afscp_FreeFid(newvfp);
949 afscp_FreeFid(dirvfp);
952 gettimeofday(&starttime, &Timezone);
954 InStatus.UnixModeBits = 0644;
955 InStatus.Mask = AFS_SETMODE + AFS_FSYNC;
956 if (newvfp == NULL) {
957 code = afscp_CreateFile(dirvfp, baseName, &InStatus, &newvfp);
959 afs_com_err(pnp, code,
960 "(could not create file %s in directory %lu.%lu.%lu)",
961 baseName, afs_printable_uint32_lu(dirvfp->fid.Volume),
962 afs_printable_uint32_lu(dirvfp->fid.Vnode),
963 afs_printable_uint32_lu(dirvfp->fid.Unique));
967 code = afscp_GetStatus(newvfp, &OutStatus);
969 afs_inet_ntoa_r(newvfp->cell->fsservers[0]->addrs[0], ipv4_addr);
970 afs_com_err(pnp, code, "(failed to get status of file %s from"
971 "server %s, code = %d)", fname, ipv4_addr, code);
972 afscp_FreeFid(newvfp);
973 afscp_FreeFid(dirvfp);
977 if ( !append && !force &&
978 (OutStatus.Length != 0 || OutStatus.Length_hi !=0 ) ) {
980 * file exists, is of non-zero length, and we're not appending
981 * to it: user must force overwrite
982 * (covers fidwrite edge case)
985 afscp_FreeFid(newvfp);
986 afscp_FreeFid(dirvfp);
987 afs_com_err(pnp, code, "(use -force to overwrite)");
992 Pos = OutStatus.Length_hi;
993 Pos = (Pos << 32) | OutStatus.Length;
996 previous = (struct wbuf *)&bufchain;
1001 * currently, these two while loops (1) read the whole source file in
1002 * before (2) writing any of it out, meaning that afsio can't deal with
1003 * files larger than the maximum amount of memory designated for
1004 * reading a file in (WRITEBUFLEN).
1005 * Consider going to a single loop, like in readFile(), though will
1006 * have implications on timing statistics (such as the "Startup to
1007 * find the file" time, below).
1010 while (Len < WRITEBUFLEN) {
1011 tbuf = calloc(1, sizeof(struct wbuf));
1015 afscp_FreeFid(newvfp);
1016 afscp_FreeFid(dirvfp);
1017 afs_com_err(pnp, code, "(cannot allocate buffer)");
1022 tbuf->buflen = BUFFLEN;
1024 afs_int64 ll, l = tbuf->buflen;
1025 if (l > synthlength)
1027 for (ll = 0; ll < l; ll += 4096) {
1028 sprintf(&tbuf->buf[ll], "Offset (0x%x, 0x%x)\n",
1029 (unsigned int)((offset + ll) >> 32),
1030 (unsigned int)((offset + ll) & 0xffffffff));
1034 tbuf->used = (afs_int32) l;
1036 tbuf->used = read(0, &tbuf->buf, tbuf->buflen); /* from stdin */
1037 if (tbuf->used == 0) {
1042 MD5_Update(&md5, &tbuf->buf, tbuf->used);
1043 previous->next = tbuf;
1047 gettimeofday(&opentime, &Timezone);
1049 fprintf(stderr, "Startup to find the file took %.3f sec.\n",
1050 time_elapsed(&starttime, &opentime));
1052 while (!code && bytes) {
1056 for (tbuf = bufchain; tbuf; tbuf = tbuf->next) {
1057 if (tbuf->used == 0)
1059 byteswritten = afscp_PWrite(newvfp, tbuf->buf,
1060 tbuf->used, Pos + xfered);
1061 if (byteswritten != tbuf->used) {
1062 fprintf(stderr,"Only %d instead of %" AFS_INT64_FMT " bytes transferred by rx_Write()\n", byteswritten, length);
1063 fprintf(stderr, "At %" AFS_UINT64_FMT " bytes from the end\n", length);
1067 xfered += tbuf->used;
1070 length -= tbuf->used;
1076 for (tbuf = bufchain; tbuf; tbuf = tbuf->next) {
1079 afs_int64 ll, l = tbuf->buflen;
1080 if (l > synthlength)
1082 for (ll = 0; ll < l; ll += 4096) {
1083 sprintf(&tbuf->buf[ll], "Offset (0x%x, 0x%x)\n",
1084 (unsigned int)((offset + ll) >> 32),
1085 (unsigned int)((offset + ll) & 0xffffffff));
1089 tbuf->used = (afs_int32) l;
1091 tbuf->used = read(0, &tbuf->buf, tbuf->buflen); /* from stdin */
1095 MD5_Update(&md5, &tbuf->buf, tbuf->used);
1097 bytes += tbuf->used;
1101 afscp_FreeFid(newvfp);
1102 afscp_FreeFid(dirvfp);
1104 gettimeofday(&writetime, &Timezone);
1106 afs_com_err(pnp, code, "(%s failed with code %d)", as->name,
1108 } else if (verbose) {
1109 summarizeDatarate(&writetime, "write");
1113 bufchain = tbuf->next;
1118 summarizeMD5(fname);