static int do_backup_phase2_client(struct config *conf, int resume, struct cntr *p1cntr, struct cntr *cntr) { int ret=0; int quit=0; char cmd; char *buf=NULL; size_t len=0; char attribs[MAXSTRING]; // For efficiency, open Windows files for the VSS data, and do not // close them until another time around the loop, when the actual // data is read. BFILE bfd; // Windows VSS headers tell us how much file // data to expect. size_t datalen=0; #ifdef HAVE_WIN32 binit(&bfd, 0); #endif struct sbuf sb; init_sbuf(&sb); if(!resume) { // Only do this bit if the server did not tell us to resume. if(async_write_str(CMD_GEN, "backupphase2") || async_read_expect(CMD_GEN, "ok")) return -1; } else if(conf->send_client_counters) { // On resume, the server might update the client with the // counters. if(recv_counters(p1cntr, cntr)) return -1; } while(!quit) { if(async_read(&cmd, &buf, &len)) { ret=-1; quit++; } else if(buf) { //logp("now: %c:%s\n", cmd, buf); if(cmd==CMD_DATAPTH) { sb.datapth=buf; buf=NULL; continue; } else if(cmd==CMD_STAT) { // Ignore the stat data - we will fill it // in again. Some time may have passed by now, // and it is best to make it as fresh as // possible. free(buf); buf=NULL; continue; } else if(cmd==CMD_FILE || cmd==CMD_ENC_FILE || cmd==CMD_METADATA || cmd==CMD_ENC_METADATA || cmd==CMD_VSS || cmd==CMD_ENC_VSS || cmd==CMD_VSS_T || cmd==CMD_ENC_VSS_T || cmd==CMD_EFS_FILE) { int forget=0; int64_t winattr=0; struct stat statbuf; char *extrameta=NULL; size_t elen=0; unsigned long long bytes=0; FILE *fp=NULL; int compression=conf->compression; sb.path=buf; buf=NULL; #ifdef HAVE_WIN32 if(win32_lstat(sb.path, &statbuf, &winattr)) #else if(lstat(sb.path, &statbuf)) #endif { logw(cntr, "Path has vanished: %s", sb.path); if(forget_file(&sb, cmd, cntr)) { ret=-1; quit++; } free_sbuf(&sb); continue; } if(conf->min_file_size && statbuf.st_size< (boffset_t)conf->min_file_size && (cmd==CMD_FILE || cmd==CMD_ENC_FILE || cmd==CMD_EFS_FILE)) { logw(cntr, "File size decreased below min_file_size after initial scan: %c:%s", cmd, sb.path); forget++; } else if(conf->max_file_size && statbuf.st_size> (boffset_t)conf->max_file_size && (cmd==CMD_FILE || cmd==CMD_ENC_FILE || cmd==CMD_EFS_FILE)) { logw(cntr, "File size increased above max_file_size after initial scan: %c:%s", cmd, sb.path); forget++; } if(!forget) { compression=in_exclude_comp(conf->excom, conf->excmcount, sb.path, conf->compression); encode_stat(attribs, &statbuf, winattr, compression); if(open_file_for_send( #ifdef HAVE_WIN32 &bfd, NULL, #else NULL, &fp, #endif sb.path, winattr, &datalen, cntr)) forget++; } if(forget) { if(forget_file(&sb, cmd, cntr)) { ret=-1; quit++; } free_sbuf(&sb); continue; } if(cmd==CMD_METADATA || cmd==CMD_ENC_METADATA || cmd==CMD_VSS || cmd==CMD_ENC_VSS #ifdef HAVE_WIN32 || conf->strip_vss #endif ) { if(get_extrameta( #ifdef HAVE_WIN32 &bfd, #else NULL, #endif sb.path, &statbuf, &extrameta, &elen, winattr, cntr, &datalen)) { logw(cntr, "Meta data error for %s", sb.path); free_sbuf(&sb); close_file_for_send(&bfd, &fp); continue; } if(extrameta) { #ifdef HAVE_WIN32 if(conf->strip_vss) { free(extrameta); extrameta=NULL; elen=0; } #endif } else { logw(cntr, "No meta data after all: %s", sb.path); free_sbuf(&sb); close_file_for_send(&bfd, &fp); continue; } } if(cmd==CMD_FILE && sb.datapth) { unsigned long long sentbytes=0; // Need to do sig/delta stuff. if(async_write_str(CMD_DATAPTH, sb.datapth) || async_write_str(CMD_STAT, attribs) || async_write_str(CMD_FILE, sb.path) || load_signature_and_send_delta( &bfd, fp, &bytes, &sentbytes, cntr, datalen)) { logp("error in sig/delta for %s (%s)\n", sb.path, sb.datapth); ret=-1; quit++; } else { do_filecounter(cntr, CMD_FILE_CHANGED, 1); do_filecounter_bytes(cntr, bytes); do_filecounter_sentbytes(cntr, sentbytes); } } else { //logp("need to send whole file: %s\n", // sb.path); // send the whole file. if((async_write_str(CMD_STAT, attribs) || async_write_str(cmd, sb.path)) || send_whole_file_w(cmd, sb.path, NULL, 0, &bytes, conf->encryption_password, cntr, compression, &bfd, fp, extrameta, elen, datalen)) { ret=-1; quit++; } else { do_filecounter(cntr, cmd, 1); do_filecounter_bytes(cntr, bytes); do_filecounter_sentbytes(cntr, bytes); } } #ifdef HAVE_WIN32 // If using Windows do not close bfd - it needs // to stay open to read VSS/file data/VSS. // It will get closed either when given a // different file path, or when this function // exits. //if(cmd!=CMD_VSS // && cmd!=CMD_ENC_VSS) // close_file_for_send(&bfd, NULL); #else close_file_for_send(NULL, &fp); #endif free_sbuf(&sb); if(extrameta) free(extrameta); } else if(cmd==CMD_WARNING) { do_filecounter(cntr, cmd, 0); free(buf); buf=NULL; } else if(cmd==CMD_GEN && !strcmp(buf, "backupphase2end")) { if(async_write_str(CMD_GEN, "okbackupphase2end")) ret=-1; quit++; } else { logp("unexpected cmd from server: %c %s\n", cmd, buf); ret=-1; quit++; free(buf); buf=NULL; } } } #ifdef HAVE_WIN32 // It is possible for a bfd to still be open. close_file_for_send(&bfd, NULL); #endif return ret; }
bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream) { BSOCK *sd = jcr->store_bsock; POOL_MEM attribs(PM_NAME), attribsExBuf(PM_NAME); char *attribsEx = NULL; int attr_stream; int comp_len; bool status; int hangup = get_hangup(); #ifdef FD_NO_SEND_TEST return true; #endif Dmsg1(300, "encode_and_send_attrs fname=%s\n", ff_pkt->fname); /** Find what data stream we will use, then encode the attributes */ if ((data_stream = select_data_stream(ff_pkt, me->compatible)) == STREAM_NONE) { /* This should not happen */ Jmsg0(jcr, M_FATAL, 0, _("Invalid file flags, no supported data stream type.\n")); return false; } encode_stat(attribs.c_str(), &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, data_stream); /** Now possibly extend the attributes */ if (IS_FT_OBJECT(ff_pkt->type)) { attr_stream = STREAM_RESTORE_OBJECT; } else { attribsEx = attribsExBuf.c_str(); attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt); } Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs.c_str(), attribsEx); jcr->lock(); jcr->JobFiles++; /* increment number of files sent */ ff_pkt->FileIndex = jcr->JobFiles; /* return FileIndex */ pm_strcpy(jcr->last_fname, ff_pkt->fname); jcr->unlock(); /* * Debug code: check if we must hangup */ if (hangup && (jcr->JobFiles > (uint32_t)hangup)) { jcr->setJobStatus(JS_Incomplete); Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d files.\n", hangup); set_hangup(0); return false; } /** * Send Attributes header to Storage daemon * <file-index> <stream> <info> */ if (!sd->fsend("%ld %d 0", jcr->JobFiles, attr_stream)) { if (!jcr->is_canceled() && !jcr->is_incomplete()) { Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror()); } return false; } Dmsg1(300, ">stored: attrhdr %s", sd->msg); /** * Send file attributes to Storage daemon * File_index * File type * Filename (full path) * Encoded attributes * Link name (if type==FT_LNK or FT_LNKSAVED) * Encoded extended-attributes (for Win32) * Delta Sequence Number * * or send Restore Object to Storage daemon * File_index * File_type * Object_index * Object_len (possibly compressed) * Object_full_len (not compressed) * Object_compression * Plugin_name * Object_name * Binary Object data * * For a directory, link is the same as fname, but with trailing * slash. For a linked file, link is the link. */ if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) { /* already stripped */ strip_path(ff_pkt); } switch (ff_pkt->type) { case FT_JUNCTION: case FT_LNK: case FT_LNKSAVED: Dmsg3(300, "Link %d %s to %s\n", jcr->JobFiles, ff_pkt->fname, ff_pkt->link); status = sd->fsend("%ld %d %s%c%s%c%s%c%s%c%u%c", jcr->JobFiles, ff_pkt->type, ff_pkt->fname, 0, attribs.c_str(), 0, ff_pkt->link, 0, attribsEx, 0, ff_pkt->delta_seq, 0); break; case FT_DIREND: case FT_REPARSE: /* Here link is the canonical filename (i.e. with trailing slash) */ status = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles, ff_pkt->type, ff_pkt->link, 0, attribs.c_str(), 0, 0, attribsEx, 0, ff_pkt->delta_seq, 0); break; case FT_PLUGIN_CONFIG: case FT_RESTORE_FIRST: comp_len = ff_pkt->object_len; ff_pkt->object_compression = 0; if (ff_pkt->object_len > 1000) { /* * Big object, compress it */ comp_len = compressBound(ff_pkt->object_len); POOLMEM *comp_obj = get_memory(comp_len); /* * FIXME: check Zdeflate error */ Zdeflate(ff_pkt->object, ff_pkt->object_len, comp_obj, comp_len); if (comp_len < ff_pkt->object_len) { ff_pkt->object = comp_obj; ff_pkt->object_compression = 1; /* zlib level 9 compression */ } else { /* * Uncompressed object smaller, use it */ comp_len = ff_pkt->object_len; } Dmsg2(100, "Object compressed from %d to %d bytes\n", ff_pkt->object_len, comp_len); } sd->msglen = Mmsg(sd->msg, "%d %d %d %d %d %d %s%c%s%c", jcr->JobFiles, ff_pkt->type, ff_pkt->object_index, comp_len, ff_pkt->object_len, ff_pkt->object_compression, ff_pkt->fname, 0, ff_pkt->object_name, 0); sd->msg = check_pool_memory_size(sd->msg, sd->msglen + comp_len + 2); memcpy(sd->msg + sd->msglen, ff_pkt->object, comp_len); /* * Note we send one extra byte so Dir can store zero after object */ sd->msglen += comp_len + 1; status = sd->send(); if (ff_pkt->object_compression) { free_and_null_pool_memory(ff_pkt->object); } break; case FT_REG: status = sd->fsend("%ld %d %s%c%s%c%c%s%c%d%c", jcr->JobFiles, ff_pkt->type, ff_pkt->fname, 0, attribs.c_str(), 0, 0, attribsEx, 0, ff_pkt->delta_seq, 0); break; default: status = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles, ff_pkt->type, ff_pkt->fname, 0, attribs.c_str(), 0, 0, attribsEx, 0, ff_pkt->delta_seq, 0); break; } if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) { unstrip_path(ff_pkt); } Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg); if (!status && !jcr->is_job_canceled()) { Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror()); } sd->signal(BNET_EOD); /* indicate end of attributes data */ return status; }
void prepare_reply(p9_obj_t *T_p9_obj, p9_obj_t *R_p9_obj, fid_list **fid_table){ fid_node *fnode; switch(T_p9_obj -> type){ case P9_TVERSION: R_p9_obj -> size = 19; /* this server only understands 9p2000 */ R_p9_obj -> type = P9_RVERSION; R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> msize = T_p9_obj -> msize; R_p9_obj -> version_len = 6; R_p9_obj -> version = (char *) malloc(20 * sizeof(char));; strcpy(R_p9_obj -> version, "9P2000"); break; case P9_TATTACH:{ int aname_len; char *aname; char *corrected_aname; aname_len = T_p9_obj -> aname_len; aname = T_p9_obj -> aname; corrected_aname = (char *) malloc(aname_len + 2); bzero(corrected_aname, aname_len + 2); strcat(corrected_aname, "/"); strcat(corrected_aname, aname); R_p9_obj -> size = 20; /* this is the size of the RMessage */ R_p9_obj -> qid = (qid_t *) malloc (sizeof(qid_t)); make_qid_from_UNIX_file(corrected_aname, R_p9_obj -> qid); /* adding the entry to the fid table */ fid_table_add_fid(fid_table, T_p9_obj -> fid, corrected_aname); free(corrected_aname); R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> type = P9_RATTACH; break; } case P9_TSTAT: R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> type = P9_RSTAT; R_p9_obj -> stat = (stat_t *) malloc(sizeof(stat_t)); fnode = fid_table_find_fid(fid_table, T_p9_obj -> fid); if(fnode == NULL){ //stating a file that does not exist in the fid table perror("TSTAT a file that is not in the fid table\n"); exit(1); } make_stat_from_UNIX_file(fnode -> path, R_p9_obj -> stat); if(R_p9_obj -> stat -> qid -> type == 128){ R_p9_obj -> stat -> length = 0; } /* Handling the case when stating a virtual disk. Should send the length of the logical disk not the actual descriptor file */ if(R_p9_obj -> stat -> qid -> type == 0 && DiskLib_IsDescriptorFile(fnode -> path)){ DiskLibError diskError; DiskHandle disk_handle; DiskLibInfo *disk_info; diskError = DiskLib_OpenWithInfo(fnode -> path, OPEN_NOIO, NULL, &disk_handle, &disk_info); if(!DiskLib_IsSuccess(diskError)){ printf(DiskLib_Err2String(diskError)); exit(1); } R_p9_obj -> stat -> length = disk_info -> capacity * DISKLIB_SECTOR_SIZE; free(disk_info); DiskLib_Close(disk_handle); } R_p9_obj -> stat_len = get_stat_length(R_p9_obj -> stat) + 2; //the stat length should be the length of the stat + the size R_p9_obj -> size = 7 + 2 + R_p9_obj -> stat_len; //stat[n] and the size field break; case P9_TWALK: /* if newfid is in use, an RERROR should be returned. The only exception is when newfid is the same as fid */ /* The case where newfid == fid should be handled separately * */ if(fid_table_find_fid(fid_table, T_p9_obj -> newfid) != NULL && T_p9_obj -> newfid != T_p9_obj -> fid){ char *error_msg; int error_len; R_p9_obj -> type = P9_RERROR; error_msg = "newfid is in use and it is not equal to fid\n"; error_len = strlen(error_msg); R_p9_obj -> size = 7 + 2 + error_len; R_p9_obj -> ename_len = error_len; R_p9_obj -> ename = error_msg; R_p9_obj -> tag = T_p9_obj -> tag; } else{ //newfid is not being used or newfid == fid (should be the same case until we change the fid_table) fid_node *fnode; fnode = fid_table_find_fid(fid_table, T_p9_obj -> fid); if(fnode == NULL || fnode -> object_handle != NULL){ if(!fnode)perror("TWALK message received with an fid that is open\n"); else perror("TWALK message received with an fid that does not exist in the fid table"); exit(1); } if(T_p9_obj -> nwname == 0){ fid_table_add_fid(fid_table, T_p9_obj -> newfid, fnode -> path); R_p9_obj -> size = 7 + 2; R_p9_obj -> type = P9_RWALK; R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> nwqid = 0; } else{ //nwname != 0 /* Check if the first element is walkable, if not an RERROR will return */ /* first get the number of nwqids */ char *path; int nwqid, i; path = (char *)malloc(1000 * sizeof(char)); strcpy(path, fnode -> path); assert(path); nwqid = 0; for(i = 0; i < T_p9_obj -> nwname; i++){ strcat(path, "/"); strcat(path, (T_p9_obj -> wname_list + i) -> wname); //fprintf(stderr, "directory path is %s\n", path); if(is_file_exists(path)) nwqid++; } if(nwqid == 0){ /* First element does not exist. return RERROR */ char *error_msg; int error_len; R_p9_obj -> type = P9_RERROR; error_msg = "No such file or directory"; error_len = strlen(error_msg); R_p9_obj -> size = 7 + 2 + error_len; R_p9_obj -> ename_len = error_len; R_p9_obj -> ename = (char *) malloc(error_len * sizeof(char) + 1); bzero(R_p9_obj -> ename, error_len + 1); strcpy(R_p9_obj -> ename, error_msg); R_p9_obj -> tag = T_p9_obj -> tag; free(path); } /* The first element is walkabale. RWALK will return */ else{ int i; bzero(path, 1000); strcpy(path, fnode -> path); R_p9_obj -> type = P9_RWALK; R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> size = 7 + 2 + nwqid * 13; R_p9_obj -> nwqid = nwqid; R_p9_obj -> wqid = (qid_t **) malloc(nwqid * sizeof(qid_t *)); for(i = 0; i < nwqid; i++){ qid_t *qid; strcat(path, "/"); strcat(path, (T_p9_obj -> wname_list + i) -> wname); qid = (qid_t *) malloc(sizeof(qid_t)); make_qid_from_UNIX_file(path, qid); R_p9_obj -> wqid[i] = qid; } /* newfid will be affected only if nwqid == nwnames */ if(nwqid == T_p9_obj -> nwname){ /* path is now the full path */ fid_node *fnode; fnode = fid_table_find_fid(fid_table, T_p9_obj -> newfid); if(fnode != NULL){ //fid = newfid case fnode -> fid = T_p9_obj -> newfid; strncpy(fnode -> path, path, 999); } else fid_table_add_fid(fid_table, T_p9_obj -> newfid, path); } free(path); } } } break; case P9_TCLUNK: /* Should remove the fid from the fid directory */ /* the remove fid should close any file or directory opened by this fid */ if(fid_table_remove_fid(fid_table, T_p9_obj -> fid) == -1){ int error_len; char *error_msg; perror("TCLUNK received for an fid that does not exist\n "); error_msg = strerror(EBADF); error_len = strlen(error_msg); R_p9_obj -> size = 7 + 2 + error_len; R_p9_obj -> ename_len = error_len; R_p9_obj -> ename = (char *) malloc(error_len + 1); bzero(R_p9_obj -> ename, error_len + 1); strcpy(R_p9_obj -> ename , error_msg); R_p9_obj -> tag = T_p9_obj -> tag; } else{ assert(fid_table_find_fid(fid_table, T_p9_obj -> fid) == NULL); R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> type = P9_RCLUNK; R_p9_obj -> size = 7; } break; case P9_TOPEN: { int p9_mode; p9_mode = 0; fnode = fid_table_find_fid(fid_table, T_p9_obj -> fid); assert(fnode != NULL); assert(fnode -> fid == T_p9_obj -> fid); assert(fnode -> object_handle == NULL); /* if fid refers to a directory, just send back the ROPEN message */ /* if fid refers to a file, open the file, change the file descriptor, and send the ROPEN message */ R_p9_obj -> size = 4 + 1 + 2 + 13 + 4; R_p9_obj -> type = P9_ROPEN; R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> qid = (qid_t *) malloc(sizeof(qid_t)); make_qid_from_UNIX_file(fnode->path, R_p9_obj -> qid); R_p9_obj -> iounit = 0; if(!DiskLib_IsDescriptorFile(fnode -> path) && (R_p9_obj -> qid -> type == 0 || R_p9_obj -> qid -> type == 2)){ //this is a regular file or a symbolic link and NOT a logical virtual disk ObjHandle *object_handle; ObjOpenParams openParams; ObjLibError objError; object_handle = (ObjHandle *) malloc(sizeof(ObjHandle)); assert((T_p9_obj -> mode & 0x10) != 0x10 ); if((T_p9_obj->mode != 0) && (T_p9_obj -> mode != 1) && (T_p9_obj -> mode != 2)){ printf("UNFAMILIAR MODE %d\n", T_p9_obj->mode); exit(1); } switch(T_p9_obj -> mode & 3){ case 0: #ifdef DEBUG printf("opening file %s for read only\n", fnode -> path); #endif p9_mode = OBJ_OPEN_ACCESS_READ; break; case 1: #ifdef DEBUG printf("opening file %s for write only\n", fnode -> path); #endif p9_mode = OBJ_OPEN_ACCESS_WRITE; break; case 2: #ifdef DEBUG printf("opening file %s for read write\n", fnode -> path); #endif p9_mode = OBJ_OPEN_ACCESS_READ | OBJ_OPEN_ACCESS_WRITE; //printf("OPENING FILE FOR READ AND WRITE IS IN OBJECT LIB\n"); break; case 3: p9_mode = OBJ_OPEN_ACCESS_READ; break; default: printf("You should never reach here\n"); exit(1); } /* The following cases are not handled since there is no ObjLib flags that represent them */ /* if (T_p9_obj -> mode & 0x10) p9_mode |= O_TRUNC; if (T_p9_obj -> mode & 0x80) p9_mode |= O_APPEND; if (T_p9_obj -> mode & 0x04) p9_mode |= O_EXCL; */ /* Opening the file based on the requested mode */ //fd = open(fnode -> path, p9_mode); /* TODO: maybe the object class type should change */ ObjLib_SetOpenParams(&openParams, fnode->path, NULL, OBJTYPE_CLASS_GENERIC, p9_mode, OBJ_OPEN, NULL, 0, NULL); objError = ObjLib_Open(&openParams, object_handle); if(!ObjLib_IsSuccess(objError)){ printf("Error opening\n"); exit(1); } /* Assigning the file descriptor to the fid node */ fnode -> object_handle = object_handle; if(fnode -> object_handle == NULL){ R_p9_obj -> type = P9_RERROR; R_p9_obj -> ename_len = strlen(strerror(errno)); R_p9_obj -> ename = (char *) malloc(R_p9_obj -> ename_len + 1); bzero(R_p9_obj -> ename, R_p9_obj -> ename_len + 1); strcpy(R_p9_obj -> ename, strerror(errno)); R_p9_obj -> size = 4 + 1 + 2 + 2 + R_p9_obj -> ename_len; } else assert(fnode -> object_handle != NULL); } /* Handling the case of a logical virtual disk */ else if(DiskLib_IsDescriptorFile(fnode -> path) && (R_p9_obj -> qid -> type == 0)){ DiskHandle *disk_handle; DiskLibError diskError; disk_handle = (DiskHandle *)malloc(sizeof(DiskHandle)); assert((T_p9_obj -> mode & 0x10) != 0x10 ); if((T_p9_obj->mode != 0) && (T_p9_obj -> mode != 1) && (T_p9_obj -> mode != 2)){ printf("UNFAMILIAR MODE %d\n", T_p9_obj->mode); exit(1); } /* probably for disks you need to open them for read and write since you can only read and write sectors */ switch(T_p9_obj -> mode & 3){ case 0: p9_mode = OPEN_PARENT | OPEN_LOCK | OPEN_RDONLY; break; case 1: p9_mode = OPEN_PARENT | OPEN_LOCK; break; case 2: p9_mode = OPEN_PARENT | OPEN_LOCK; break; case 3: p9_mode = OPEN_PARENT | OPEN_LOCK | OPEN_RDONLY; break; default: printf("You should have never reached this point"); exit(1); } diskError = DiskLib_Open(fnode -> path, p9_mode, NULL, disk_handle); if(!DiskLib_IsSuccess(diskError)){ printf("Error opening virtual disk during TOpen"); exit(1); } /* adding the disk handle to the fnode */ fnode -> disk_handle = disk_handle; assert(fnode -> disk_handle != NULL); } else{ //file is a directory fnode -> dd = opendir(fnode -> path); if(fnode -> dd == NULL){ R_p9_obj -> type = P9_RERROR; R_p9_obj -> ename_len = strlen(strerror(errno)); R_p9_obj -> ename = (char *) malloc(R_p9_obj -> ename_len + 1); bzero(R_p9_obj -> ename, R_p9_obj -> ename_len + 1); strcpy(R_p9_obj -> ename, strerror(errno)); R_p9_obj -> size = 4 + 1 + 2 + 2 + R_p9_obj -> ename_len; } /* handle permissions and rw access */ } break; } // ending case scope case P9_TREAD: {//defining a scope in the case statement int fid; uint8_t *data; //fprintf(stderr, "I am here!"); fid = T_p9_obj -> fid; fnode = fid_table_find_fid(fid_table, fid); assert(fnode != NULL); //fprintf(stderr, "I am here tooooo\n"); data = (uint8_t *) malloc(T_p9_obj -> count * sizeof(uint8_t)); //fprintf(stderr, "before zeroing\n"); bzero(data, T_p9_obj -> count); //fprintf(stderr, "after zeroing\n"); /* handling the directory case */ assert(fnode); //fprintf(stderr, "fd is %d\n", fnode -> fd); if(fnode -> object_handle == NULL && fnode -> disk_handle == NULL){ //this must be a directory then struct dirent *entry; int idx; char *newpathname; newpathname = (char *) malloc(1000 * sizeof(char)); idx = 0; assert(fnode -> dd); #ifdef DEBUG //fprintf(stderr, "Attempting to read directory %s\n", fnode -> dd); #endif while((entry = readdir(fnode -> dd))){ #ifdef DEBUG //fprintf(stderr, "entry is %s\n", entry->d_name); #endif char *entry_name; stat_t *s; bzero(newpathname, 1000); strcpy(newpathname, fnode -> path); if((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) continue; entry_name = entry->d_name; newpathname = strcat(newpathname, "/"); newpathname = strcat(newpathname, entry_name); s = (stat_t *) malloc(sizeof(stat_t)); #ifdef DEBUG //fprintf(stderr, "Attempting to create stat now\n"); //fprintf(stderr, "stating pathname: %s\n", newpathname); #endif make_stat_from_UNIX_file(newpathname, s); //int_to_buffer_bytes(get_stat_length(s) + 2, data, idx, 2); //idx += 2; if(DiskLib_IsDescriptorFile(newpathname)){ DiskLibError diskError; DiskHandle disk_handle; DiskLibInfo *disk_info; diskError = DiskLib_OpenWithInfo(newpathname, OPEN_NOIO, NULL, &disk_handle, &disk_info); if(!DiskLib_IsSuccess(diskError)){ printf(DiskLib_Err2String(diskError)); exit(1); } s -> length = disk_info -> capacity * DISKLIB_SECTOR_SIZE; free(disk_info); DiskLib_Close(disk_handle); } encode_stat(s, data, idx, get_stat_length(s)); idx += (2 + get_stat_length(s)); destroy_stat(s); /* just a quick hack */ if(idx > ((90.0 / 100.0) * (float)(T_p9_obj->count))) break; //this is a safety factor to make sure we are not exceeding the Tcount assert(idx <= T_p9_obj -> count); } free(newpathname); R_p9_obj -> count = idx; R_p9_obj -> data = data; R_p9_obj -> size = 4 + 2 + 4 + 1 + R_p9_obj -> count; R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> type = P9_RREAD; } /* handling the file case */ else if (fnode -> disk_handle == NULL){ /* not a logical virtual disk file */ int count, read_bytes; //fprintf(stderr, "inside else\n"); count = T_p9_obj -> count; assert(ObjLib_IsHandleValid(*(fnode -> object_handle))); read_bytes = ESX_read(fnode -> object_handle, data, T_p9_obj -> offset, count); if(read_bytes >= 0){ R_p9_obj -> count = read_bytes; R_p9_obj -> data = data; R_p9_obj -> size = 4 + 2 + 4 + 1 + R_p9_obj -> count; R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> type = P9_RREAD; } else{ R_p9_obj -> type = P9_RERROR; R_p9_obj -> ename_len = strlen(strerror(errno)); R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> ename = (char *) malloc(R_p9_obj -> ename_len + 1); bzero(R_p9_obj -> ename, R_p9_obj -> ename_len + 1); strcpy(R_p9_obj -> ename, strerror(errno)); R_p9_obj -> size = 4 + 1 + 2 + 2 + R_p9_obj -> ename_len; } } /* Now handling the logical virtual disk case */ else{ int count, read_bytes; count = T_p9_obj -> count; //assert(DiskLib_IsHandleValid(fnode -> disk_handle)); read_bytes = ESX_Vdisk_Read(fnode -> disk_handle, data, T_p9_obj -> offset, count); if(read_bytes >= 0){ R_p9_obj -> count = read_bytes; R_p9_obj -> data = data; R_p9_obj -> size = 4 + 2 + 4 + 1 + R_p9_obj -> count; R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> type = P9_RREAD; } else{ R_p9_obj -> type = P9_RERROR; R_p9_obj -> ename_len = strlen(strerror(errno)); R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> ename = (char *) malloc(R_p9_obj -> ename_len + 1); bzero(R_p9_obj -> ename, R_p9_obj -> ename_len + 1); strcpy(R_p9_obj -> ename, strerror(errno)); R_p9_obj -> size = 4 + 1 + 2 + 2 + R_p9_obj -> ename_len; } } break; }//ending scope case P9_TWRITE: { int fid, count, write_count; #ifdef DEBUG int i; #endif unsigned long long offset; fid_node *fnode; R_p9_obj -> size = 11; R_p9_obj -> type = P9_RWRITE; R_p9_obj -> tag = T_p9_obj -> tag; fid = T_p9_obj -> fid; offset = T_p9_obj -> offset; count = T_p9_obj -> count; fnode = fid_table_find_fid(fid_table, fid); assert(fnode != NULL); assert((fnode -> object_handle != NULL) || (fnode -> disk_handle != NULL)); /* file must be open */ #ifdef DEBUG printf("DATA\n"); for(i = 0; i < T_p9_obj -> count; i++){ printf("%d ", T_p9_obj -> data[i]); } #endif if(fnode -> object_handle) write_count = ESX_write(fnode -> object_handle, offset, T_p9_obj -> data, count); /* this is handling the logical virtual disk write case */ else write_count = ESX_Vdisk_Write(fnode -> disk_handle, offset, T_p9_obj -> data, count); R_p9_obj -> count = write_count; break; }//ending scope case P9_TCREATE: { int fid; struct stat *s; uint32_t perm; char *newpathname; fid = T_p9_obj -> fid; fnode = fid_table_find_fid(fid_table, fid); if(fnode == NULL){ perror("Trying to create a new file in a directory that does not exist in the fid_table\n"); exit(1); } s = (struct stat *)malloc(sizeof(struct stat)); if(lstat(fnode -> path, s)==0){ if(!S_ISDIR(s->st_mode)){ perror("The fid belongs to a file not a directory. Can't execute TCREATE\n"); } } else{ perror("cant stat fnode->path\n"); exit(1); } perm = T_p9_obj -> perm; if((perm & 0x80000000) == 0x80000000){ //this is a directory create_directory(fnode->path, T_p9_obj -> name); } else{//a file needs to be create create_file(fnode->path, T_p9_obj -> name, perm); } /* now the newly created file needs to be opened */ R_p9_obj -> size = 4 + 1 + 2 + 13 + 4; R_p9_obj -> type = P9_RCREATE; R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> qid = (qid_t *) malloc(sizeof(qid_t)); newpathname = (char *)malloc(1000); bzero(newpathname, 1000); strcat(newpathname, fnode->path); strcat(newpathname, "/"); strcat(newpathname, T_p9_obj -> name); #ifdef DEBUG printf("ATTEMPTING TO CREATE %s\n", newpathname); #endif /* this fid should represent the newly created file now */ fnode -> path = newpathname; fnode -> dd = 0; fnode -> object_handle = NULL; make_qid_from_UNIX_file(fnode->path, R_p9_obj -> qid); R_p9_obj -> iounit = 0; if(R_p9_obj -> qid -> type == 0 ){ //this is a regular file int p9_mode; ObjHandle *object_handle; ObjOpenParams openParams; ObjLibError objError; object_handle = (ObjHandle *) malloc(sizeof(ObjHandle)); assert((T_p9_obj -> mode & 0x10) != 0x10 ); if((T_p9_obj->mode != 0) && (T_p9_obj -> mode != 1) && (T_p9_obj -> mode != 2)){ printf("UNFAMILIAR MODE %d\n", T_p9_obj->mode); exit(1); } p9_mode = 0; switch(T_p9_obj -> mode & 3){ case 0: #ifdef DEBUG printf("opening file %s for read only\n", fnode -> path); #endif p9_mode = OBJ_OPEN_ACCESS_READ; break; case 1: #ifdef DEBUG printf("opening file %s for write only\n", fnode -> path); #endif p9_mode = OBJ_OPEN_ACCESS_WRITE; break; case 2: #ifdef DEBUG printf("opening file %s for read write\n", fnode -> path); #endif p9_mode = OBJ_OPEN_ACCESS_READ | OBJ_OPEN_ACCESS_WRITE; //printf("OPENING FILE FOR READ AND WRITE IS NOT SUPPORTED IN OBJECT LIB\n"); break; case 3: p9_mode = OBJ_OPEN_ACCESS_READ; break; default: printf("You should never reach here\n"); exit(1); break; } ObjLib_SetOpenParams(&openParams, fnode->path, NULL, OBJTYPE_CLASS_GENERIC, p9_mode, OBJ_OPEN, NULL, 0, NULL); objError = ObjLib_Open(&openParams, object_handle); if(!ObjLib_IsSuccess(objError)){ printf("Error opening\n"); exit(1); } /* Assigning the file descriptor to the fid node */ fnode -> object_handle = object_handle; if(fnode -> object_handle == NULL){ R_p9_obj -> type = P9_RERROR; R_p9_obj -> ename_len = strlen(strerror(errno)); R_p9_obj -> ename = (char *) malloc(R_p9_obj -> ename_len + 1); bzero(R_p9_obj -> ename, R_p9_obj -> ename_len + 1); strcpy(R_p9_obj -> ename, strerror(errno)); R_p9_obj -> size = 4 + 1 + 2 + 2 + R_p9_obj -> ename_len; } else{ assert(fnode -> object_handle != NULL); } } else{ //file is a directory fnode -> dd = opendir(fnode -> path); /* handle permissions and rw access */ } free(s); //free the temporary allocated stat data structure break; }//end scope case P9_TREMOVE:{ int fid; R_p9_obj -> size = 7; R_p9_obj -> type = P9_RREMOVE; R_p9_obj -> tag = T_p9_obj -> tag; fid = T_p9_obj -> fid; fnode = fid_table_find_fid(fid_table, fid); assert(fnode != NULL); assert(fnode->path != NULL); if(UNIX_remove(fnode->path) != 0){ perror("failed to remove\n"); exit(1); } if(fid_table_remove_fid(fid_table, fid) == -1){ perror("TRREMOVE"); exit(1); } assert(fid_table_find_fid(fid_table, T_p9_obj -> fid) == NULL); break; }//end scope case P9_TWSTAT: { int fid; fid_node *fnode; stat_t *s_new; stat_t *s_old; fid = T_p9_obj -> fid; s_new = T_p9_obj -> stat; fnode = fid_table_find_fid(fid_table, fid); if(fnode == NULL){ perror("writing stat to non existing file\n"); exit(1); } s_old = (stat_t *)malloc(sizeof(stat_t)); make_stat_from_UNIX_file(fnode->path, s_old); /* now you have s_new and s_old. Check differences and call the appropriate UNIX api */ /* it doesn't make any sense to change the type, dev, qid, atime, mtime, muid */ /* only name, uid, gid, permission part of the mode can be changed * */ /* it does not make any sense to change the length */ if((strcmp(s_new -> name, "")!= 0) && (strcmp(s_old -> name, s_new -> name) != 0)){ #ifdef DEBUG printf("RENAMING: %s to %s\n", s_old -> name, s_new -> name); #endif if(T_p9_obj -> stat -> qid -> type == 128){ /* TODO: check permissions */ UNIX_rename_directory(fnode -> path, s_new -> name); } else{ /* TODO: check permission */ UNIX_rename_file(fnode->path, s_new->name); } } if(s_new -> mode != 0xffffffff && s_old -> mode != s_new -> mode){ /* only change the permissions */ #ifdef DEBUG printf("MODE required to change from %d to %d!\n", s_old -> mode, s_new -> mode); #endif UNIX_change_permissions(fnode->path, s_new -> mode); } R_p9_obj -> size = 7; R_p9_obj -> type = P9_RWSTAT; R_p9_obj -> tag = T_p9_obj -> tag; /* also gid can be changed but that should be taken care of later */ destroy_stat(s_old); break; }//end of scope case P9_TFLUSH: R_p9_obj -> size = 7; R_p9_obj -> tag = T_p9_obj -> tag; R_p9_obj -> type = P9_RFLUSH; break; default: break; }; }
array_t *get_dir (const char * path, int flags) { array_t *v; int i, count = 0; #ifndef WIN32 DIR *dirp; #endif int namelen, do_match = 0; #ifndef WIN32 #ifdef USE_STRUCT_DIRENT struct dirent *de; #else struct direct *de; #endif #endif struct stat st; char *endtemp; char temppath[MAX_FNAME_SIZE + MAX_PATH_LEN + 2]; char regexppath[MAX_FNAME_SIZE + MAX_PATH_LEN + 2]; char *p; #ifdef WIN32 struct _finddata_t FindBuffer; long FileHandle, FileCount; #endif if (!path) return 0; path = check_valid_path(path, current_object, "stat", 0); if (path == 0) return 0; if (strlen(path) < 2) { temppath[0] = path[0] ? path[0] : '.'; temppath[1] = '\000'; p = temppath; } else { strncpy(temppath, path, MAX_FNAME_SIZE + MAX_PATH_LEN + 1); temppath[MAX_FNAME_SIZE + MAX_PATH_LEN + 1] = '\0'; /* * If path ends with '/' or "/." remove it */ if ((p = strrchr(temppath, '/')) == 0) p = temppath; if (p[0] == '/' && ((p[1] == '.' && p[2] == '\0') || p[1] == '\0')) *p = '\0'; } if (stat(temppath, &st) < 0) { if (*p == '\0') return 0; if (p != temppath) { strcpy(regexppath, p + 1); *p = '\0'; } else { strcpy(regexppath, p); strcpy(temppath, "."); } do_match = 1; } else if (*p != '\0' && strcmp(temppath, ".")) { if (*p == '/' && *(p + 1) != '\0') p++; v = allocate_empty_array(1); encode_stat(&v->item[0], flags, p, &st); return v; } #ifdef WIN32 FileHandle = -1; FileCount = 1; /* strcat(temppath, "\\*"); */ strcat(temppath, "/*"); if ((FileHandle = _findfirst(temppath, &FindBuffer)) == -1) return 0; #else if ((dirp = opendir(temppath)) == 0) return 0; #endif /* * Count files */ #ifdef WIN32 do { if (!do_match && (!strcmp(FindBuffer.name, ".") || !strcmp(FindBuffer.name, ".."))) { continue; } if (do_match && !match_string(regexppath, FindBuffer.name)) { continue; } count++; if (count >= max_array_size) { break; } } while (!_findnext(FileHandle, &FindBuffer)); _findclose(FileHandle); #else for (de = readdir(dirp); de; de = readdir(dirp)) { #ifdef USE_STRUCT_DIRENT namelen = strlen(de->d_name); #else namelen = de->d_namlen; #endif if (!do_match && (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)) continue; if (do_match && !match_string(regexppath, de->d_name)) continue; count++; if (count >= max_array_size) break; } #endif /* * Make array and put files on it. */ v = allocate_empty_array(count); if (count == 0) { /* This is the easy case :-) */ #ifndef WIN32 closedir(dirp); #endif return v; } #ifdef WIN32 FileHandle = -1; if ((FileHandle = _findfirst(temppath, &FindBuffer)) == -1) return 0; endtemp = temppath + strlen(temppath) - 2; *endtemp = 0; /* strcat(endtemp++, "\\"); */ strcat(endtemp++, "/"); i = 0; do { if (!do_match && (!strcmp(FindBuffer.name, ".") || !strcmp(FindBuffer.name, ".."))) continue; if (do_match && !match_string(regexppath, FindBuffer.name)) continue; if (flags == -1) { strcpy(endtemp, FindBuffer.name); stat(temppath, &st); } encode_stat(&v->item[i], flags, FindBuffer.name, &st); i++; } while (!_findnext(FileHandle, &FindBuffer)); _findclose(FileHandle); #else /* WIN32 */ rewinddir(dirp); endtemp = temppath + strlen(temppath); strcat(endtemp++, "/"); for (i = 0, de = readdir(dirp); i < count; de = readdir(dirp)) { #ifdef USE_STRUCT_DIRENT namelen = strlen(de->d_name); #else namelen = de->d_namlen; #endif if (!do_match && (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)) continue; if (do_match && !match_string(regexppath, de->d_name)) continue; de->d_name[namelen] = '\0'; if (flags == -1) { /* * We'll have to .... sigh.... stat() the file to get some add'tl * info. */ strcpy(endtemp, de->d_name); stat(temppath, &st);/* We assume it works. */ } encode_stat(&v->item[i], flags, de->d_name, &st); i++; } closedir(dirp); #endif /* OS2 */ /* Sort the names. */ qsort((void *) v->item, count, sizeof v->item[0], (flags == -1) ? parrcmp : pstrcmp); return v; }
int send_file(FF_PKT *ff, bool top_level, struct config *conf, struct cntr *p1cntr) { char msg[128]=""; char attribs[MAXSTRING]; if(!file_is_included(conf->incexcdir, conf->iecount, conf->incext, conf->incount, conf->excext, conf->excount, conf->increg, conf->ircount, conf->excreg, conf->ercount, ff->fname, top_level)) return 0; #ifdef HAVE_WIN32 // Useful Windows attributes debug /* printf("\n%llu", ff->winattr); printf("\n%s\n", ff->fname); if(ff->winattr & FILE_ATTRIBUTE_READONLY) printf("readonly\n"); if(ff->winattr & FILE_ATTRIBUTE_HIDDEN) printf("hidden\n"); if(ff->winattr & FILE_ATTRIBUTE_SYSTEM) printf("system\n"); if(ff->winattr & FILE_ATTRIBUTE_DIRECTORY) printf("directory\n"); if(ff->winattr & FILE_ATTRIBUTE_ARCHIVE) printf("archive\n"); if(ff->winattr & FILE_ATTRIBUTE_DEVICE) printf("device\n"); if(ff->winattr & FILE_ATTRIBUTE_NORMAL) printf("normal\n"); if(ff->winattr & FILE_ATTRIBUTE_TEMPORARY) printf("temporary\n"); if(ff->winattr & FILE_ATTRIBUTE_SPARSE_FILE) printf("sparse\n"); if(ff->winattr & FILE_ATTRIBUTE_REPARSE_POINT) printf("reparse\n"); if(ff->winattr & FILE_ATTRIBUTE_COMPRESSED) printf("compressed\n"); if(ff->winattr & FILE_ATTRIBUTE_OFFLINE) printf("offline\n"); if(ff->winattr & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) printf("notcont\n"); if(ff->winattr & FILE_ATTRIBUTE_ENCRYPTED) printf("encrypted\n"); if(ff->winattr & FILE_ATTRIBUTE_VIRTUAL) printf("virtual\n"); */ if(ff->winattr & FILE_ATTRIBUTE_ENCRYPTED) { // if(ff->type!=FT_DIREND) // logw(p1cntr, "EFS not yet supported: %s", ff->fname); // return 0; if(ff->type==FT_REGE || ff->type==FT_REG || ff->type==FT_DIRBEGIN) { encode_stat(attribs, &ff->statp, ff->winattr, conf->compression); if(async_write_str(CMD_STAT, attribs) || async_write_str(CMD_EFS_FILE, ff->fname)) return -1; do_filecounter(p1cntr, CMD_EFS_FILE, 1); if(ff->type==FT_REG) do_filecounter_bytes(p1cntr, (unsigned long long)ff->statp.st_size); return 0; } else if(ff->type==FT_DIREND) return 0; else { // Hopefully, here is never reached. logw(p1cntr, "EFS type %d not yet supported: %s", ff->type, ff->fname); return 0; } } #endif //logp("%d: %s\n", ff->type, ff->fname); switch (ff->type) { case FT_LNKSAVED: //printf("Lnka: %s -> %s\n", ff->fname, ff->link); encode_stat(attribs, &ff->statp, ff->winattr, conf->compression); if(async_write_str(CMD_STAT, attribs) || async_write_str(CMD_HARD_LINK, ff->fname) || async_write_str(CMD_HARD_LINK, ff->link)) return -1; do_filecounter(p1cntr, CMD_HARD_LINK, 1); // At least FreeBSD 8.2 can have different xattrs on hard links. if(maybe_send_extrameta(ff->fname, CMD_HARD_LINK, attribs, p1cntr)) return -1; break; case FT_FIFO: case FT_REGE: case FT_REG: encode_stat(attribs, &ff->statp, ff->winattr, in_exclude_comp(conf->excom, conf->excmcount, ff->fname, conf->compression)); if(async_write_str(CMD_STAT, attribs) || async_write_str(filesymbol, ff->fname)) return -1; do_filecounter(p1cntr, filesymbol, 1); if(ff->type==FT_REG) do_filecounter_bytes(p1cntr, (unsigned long long)ff->statp.st_size); if(maybe_send_extrameta(ff->fname, filesymbol, attribs, p1cntr)) return -1; break; case FT_LNK: //printf("link: %s -> %s\n", ff->fname, ff->link); encode_stat(attribs, &ff->statp, ff->winattr, conf->compression); if(async_write_str(CMD_STAT, attribs) || async_write_str(CMD_SOFT_LINK, ff->fname) || async_write_str(CMD_SOFT_LINK, ff->link)) return -1; do_filecounter(p1cntr, CMD_SOFT_LINK, 1); if(maybe_send_extrameta(ff->fname, CMD_SOFT_LINK, attribs, p1cntr)) return -1; break; case FT_DIREND: return 0; case FT_NOFSCHG: case FT_DIRBEGIN: case FT_REPARSE: case FT_JUNCTION: { char errmsg[100] = ""; if (ff->type == FT_NOFSCHG) snprintf(errmsg, sizeof(errmsg), _("\t[will not descend: file system change not allowed]")); if(*errmsg) { snprintf(msg, sizeof(msg), "%s%s%s\n", "Dir: ", ff->fname, errmsg); logw(p1cntr, "%s", msg); } else { encode_stat(attribs, &ff->statp, ff->winattr, conf->compression); if(async_write_str(CMD_STAT, attribs)) return -1; #if defined(WIN32_VSS) if(async_write_str(filesymbol, ff->fname)) return -1; do_filecounter(p1cntr, filesymbol, 1); #else if(async_write_str(CMD_DIRECTORY, ff->fname)) return -1; do_filecounter(p1cntr, CMD_DIRECTORY, 1); if(maybe_send_extrameta(ff->fname, CMD_DIRECTORY, attribs, p1cntr)) return -1; #endif } } break; case FT_SPEC: // special file - fifo, socket, device node... encode_stat(attribs, &ff->statp, ff->winattr, conf->compression); if(async_write_str(CMD_STAT, attribs) || async_write_str(CMD_SPECIAL, ff->fname)) return -1; do_filecounter(p1cntr, CMD_SPECIAL, 1); if(maybe_send_extrameta(ff->fname, CMD_SPECIAL, attribs, p1cntr)) return -1; break; case FT_NOACCESS: logw(p1cntr, _("Err: Could not access %s: %s"), ff->fname, strerror(errno)); break; case FT_NOFOLLOW: logw(p1cntr, _("Err: Could not follow ff->link %s: %s"), ff->fname, strerror(errno)); break; case FT_NOSTAT: logw(p1cntr, _("Err: Could not stat %s: %s"), ff->fname, strerror(errno)); break; case FT_NOCHG: logw(p1cntr, _("Skip: File not saved. No change. %s"), ff->fname); break; case FT_ISARCH: logw(p1cntr, _("Err: Attempt to backup archive. Not saved. %s"), ff->fname); break; case FT_NOOPEN: logw(p1cntr, _("Err: Could not open directory %s: %s"), ff->fname, strerror(errno)); break; case FT_RAW: logw(p1cntr, _("Err: Raw partition: %s"), ff->fname); break; default: logw(p1cntr, _("Err: Unknown file ff->type %d: %s"), ff->type, ff->fname); break; } return 0; }
static int do_backup_phase2_client(struct config *conf, int resume, struct cntr *cntr) { int ret=0; int quit=0; char cmd; char *buf=NULL; size_t len=0; char attribs[MAXSTRING]; struct sbuf sb; init_sbuf(&sb); if(!resume) { // Only do this bit if the server did not tell us to resume. if(async_write_str(CMD_GEN, "backupphase2") || async_read_expect(CMD_GEN, "ok")) return -1; } while(!quit) { if(async_read(&cmd, &buf, &len)) { ret=-1; quit++; } else if(buf) { //logp("now: %c:%s\n", cmd, buf); if(cmd==CMD_DATAPTH) { sb.datapth=buf; buf=NULL; continue; } else if(cmd==CMD_STAT) { // Ignore the stat data - we will fill it // in again. Some time may have passed by now, // and it is best to make it as fresh as // possible. free(buf); buf=NULL; continue; } else if(cmd==CMD_FILE || cmd==CMD_ENC_FILE || cmd==CMD_METADATA || cmd==CMD_ENC_METADATA || cmd==CMD_EFS_FILE) { int forget=0; int64_t winattr=0; struct stat statbuf; char *extrameta=NULL; size_t elen=0; unsigned long long bytes=0; BFILE bfd; FILE *fp=NULL; sb.path=buf; buf=NULL; #ifdef HAVE_WIN32 if(win32_lstat(sb.path, &statbuf, &winattr)) #else if(lstat(sb.path, &statbuf)) #endif { logw(cntr, "Path has vanished: %s", sb.path); if(forget_file(&sb, cmd, cntr)) { ret=-1; quit++; } free_sbuf(&sb); continue; } if(conf->min_file_size && statbuf.st_size<(boffset_t)conf->min_file_size) { logw(cntr, "File size decreased below min_file_size after initial scan: %s", sb.path); forget++; } else if(conf->max_file_size && statbuf.st_size>(boffset_t)conf->max_file_size) { logw(cntr, "File size increased above max_file_size after initial scan: %s", sb.path); forget++; } if(!forget) { encode_stat(attribs, &statbuf, winattr); if(open_file_for_send(&bfd, &fp, sb.path, winattr, cntr)) forget++; } if(forget) { if(forget_file(&sb, cmd, cntr)) { ret=-1; quit++; } free_sbuf(&sb); continue; } if(cmd==CMD_METADATA || cmd==CMD_ENC_METADATA) { if(get_extrameta(sb.path, &statbuf, &extrameta, &elen, cntr)) { logw(cntr, "Meta data error for %s", sb.path); free_sbuf(&sb); close_file_for_send(&bfd, &fp); continue; } if(!extrameta) { logw(cntr, "No meta data after all: %s", sb.path); free_sbuf(&sb); close_file_for_send(&bfd, &fp); continue; } } if(cmd==CMD_FILE && sb.datapth) { unsigned long long sentbytes=0; // Need to do sig/delta stuff. if(async_write_str(CMD_DATAPTH, sb.datapth) || async_write_str(CMD_STAT, attribs) || async_write_str(CMD_FILE, sb.path) || load_signature_and_send_delta( &bfd, fp, &bytes, &sentbytes, cntr)) { logp("error in sig/delta for %s (%s)\n", sb.path, sb.datapth); ret=-1; quit++; } else { do_filecounter(cntr, CMD_FILE_CHANGED, 1); do_filecounter_bytes(cntr, bytes); do_filecounter_sentbytes(cntr, sentbytes); } } else { //logp("need to send whole file: %s\n", // sb.path); // send the whole file. if(async_write_str(CMD_STAT, attribs) || async_write_str(cmd, sb.path) || send_whole_file_w(cmd, sb.path, NULL, 0, &bytes, conf->encryption_password, cntr, conf->compression, &bfd, fp, extrameta, elen)) { ret=-1; quit++; } else { do_filecounter(cntr, cmd, 1); do_filecounter_bytes(cntr, bytes); do_filecounter_sentbytes(cntr, bytes); } } close_file_for_send(&bfd, &fp); free_sbuf(&sb); if(extrameta) free(extrameta); } else if(cmd==CMD_WARNING) { do_filecounter(cntr, cmd, 0); free(buf); buf=NULL; } else if(cmd==CMD_GEN && !strcmp(buf, "backupphase2end")) { if(async_write_str(CMD_GEN, "okbackupphase2end")) ret=-1; quit++; } else { logp("unexpected cmd from server: %c %s\n", cmd, buf); ret=-1; quit++; free(buf); buf=NULL; } } } return ret; }
/* * Called here by find() for each file. * * Find the file, compute the MD5 or SHA1 and send it back to the Director */ static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level) { POOL_MEM attribs(PM_NAME), attribsEx(PM_NAME); int digest_stream = STREAM_NONE; int status; DIGEST *digest = NULL; BSOCK *dir; if (job_canceled(jcr)) { return 0; } dir = jcr->dir_bsock; jcr->num_files_examined++; /* bump total file count */ switch (ff_pkt->type) { case FT_LNKSAVED: /* Hard linked, file already saved */ Dmsg2(30, "FT_LNKSAVED saving: %s => %s\n", ff_pkt->fname, ff_pkt->link); break; case FT_REGE: Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname); break; case FT_REG: Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname); break; case FT_LNK: Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link); break; case FT_DIRBEGIN: jcr->num_files_examined--; /* correct file count */ return 1; /* ignored */ case FT_REPARSE: case FT_JUNCTION: case FT_DIREND: Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname); break; case FT_SPEC: Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname); break; case FT_RAW: Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname); break; case FT_FIFO: Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname); break; case FT_NOACCESS: { berrno be; be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 1, _(" Could not access %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror()); jcr->JobErrors++; return 1; } case FT_NOFOLLOW: { berrno be; be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 1, _(" Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror()); jcr->JobErrors++; return 1; } case FT_NOSTAT: { berrno be; be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 1, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror()); jcr->JobErrors++; return 1; } case FT_DIRNOCHG: case FT_NOCHG: Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname); return 1; case FT_ISARCH: Jmsg(jcr, M_SKIPPED, 1, _(" Archive file skipped: %s\n"), ff_pkt->fname); return 1; case FT_NORECURSE: Jmsg(jcr, M_SKIPPED, 1, _(" Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname); ff_pkt->type = FT_DIREND; /* directory entry was backed up */ break; case FT_NOFSCHG: Jmsg(jcr, M_SKIPPED, 1, _(" File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname); return 1; case FT_PLUGIN_CONFIG: case FT_RESTORE_FIRST: return 1; /* silently skip */ case FT_NOOPEN: { berrno be; be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 1, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror()); jcr->JobErrors++; return 1; } default: Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname); jcr->JobErrors++; return 1; } /* Encode attributes and possibly extend them */ encode_stat(attribs.c_str(), &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, 0); encode_attribsEx(jcr, attribsEx.c_str(), ff_pkt); jcr->lock(); jcr->JobFiles++; /* increment number of files sent */ pm_strcpy(jcr->last_fname, ff_pkt->fname); jcr->unlock(); /* * Send file attributes to Director * File_index * Stream * Verify Options * Filename (full path) * Encoded attributes * Link name (if type==FT_LNK) * For a directory, link is the same as fname, but with trailing * slash. For a linked file, link is the link. */ /* Send file attributes to Director (note different format than for Storage) */ Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname); if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) { status = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname, 0, attribs.c_str(), 0, ff_pkt->link, 0); } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE || ff_pkt->type == FT_JUNCTION) { /* Here link is the canonical filename (i.e. with trailing slash) */ status = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link, 0, attribs.c_str(), 0, 0); } else { status = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname, 0, attribs.c_str(), 0, 0); } Dmsg2(20, "filed>dir: attribs len=%d: msg=%s\n", dir->msglen, dir->msg); if (!status) { Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir)); return 0; } /* * The remainder of the function is all about getting the checksum. * First we initialise, then we read files, other streams and Finder Info. */ if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) && ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) { /* * Create our digest context. If this fails, the digest will be set to NULL * and not used. */ if (ff_pkt->flags & FO_MD5) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5); digest_stream = STREAM_MD5_DIGEST; } else if (ff_pkt->flags & FO_SHA1) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1); digest_stream = STREAM_SHA1_DIGEST; } else if (ff_pkt->flags & FO_SHA256) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256); digest_stream = STREAM_SHA256_DIGEST; } else if (ff_pkt->flags & FO_SHA512) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512); digest_stream = STREAM_SHA512_DIGEST; } /* Did digest initialization fail? */ if (digest_stream != STREAM_NONE && digest == NULL) { Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"), stream_to_ascii(digest_stream)); } /* compute MD5 or SHA1 hash */ if (digest) { char md[CRYPTO_DIGEST_MAX_SIZE]; uint32_t size; size = sizeof(md); if (digest_file(jcr, ff_pkt, digest) != 0) { jcr->JobErrors++; goto good_rtn; } if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) { char *digest_buf; const char *digest_name; digest_buf = (char *)malloc(BASE64_SIZE(size)); digest_name = crypto_digest_name(digest); bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true); Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf); dir->fsend("%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf, digest_name, jcr->JobFiles); Dmsg3(20, "filed>dir: %s len=%d: msg=%s\n", digest_name, dir->msglen, dir->msg); free(digest_buf); } } } good_rtn: if (digest) { crypto_digest_free(digest); } return 1; }
void test_base64(void **state) { (void) state; /* unused */ /* * Test the base64 routines by encoding and decoding * lstat() packets. */ char where[500]; int i; char *fname; struct stat statp; struct stat statn; int debug_level = 0; char *p; int32_t j; time_t t = 1028712799; fname = BINARYNAME; base64_init(); if (lstat(fname, &statp) < 0) { berrno be; printf("Cannot stat %s: %s\n", fname, be.bstrerror(errno)); } encode_stat(where, &statp, sizeof(statp), 0, 0); //printf("Encoded stat=%s\n", where); #ifdef xxx p = where; p += to_base64((int64_t)(statp.st_atime), p); *p++ = ' '; p += to_base64((int64_t)t, p); printf("%s %s\n", fname, where); printf("%s %lld\n", "st_dev", (int64_t)statp.st_dev); printf("%s %lld\n", "st_ino", (int64_t)statp.st_ino); printf("%s %lld\n", "st_mode", (int64_t)statp.st_mode); printf("%s %lld\n", "st_nlink", (int64_t)statp.st_nlink); printf("%s %lld\n", "st_uid", (int64_t)statp.st_uid); printf("%s %lld\n", "st_gid", (int64_t)statp.st_gid); printf("%s %lld\n", "st_rdev", (int64_t)statp.st_rdev); printf("%s %lld\n", "st_size", (int64_t)statp.st_size); printf("%s %lld\n", "st_blksize", (int64_t)statp.st_blksize); printf("%s %lld\n", "st_blocks", (int64_t)statp.st_blocks); printf("%s %lld\n", "st_atime", (int64_t)statp.st_atime); printf("%s %lld\n", "st_mtime", (int64_t)statp.st_mtime); printf("%s %lld\n", "st_ctime", (int64_t)statp.st_ctime); #endif //printf("%s: len=%d val=%s\n", fname, strlen(where), where); decode_stat(where, &statn, sizeof(statn), &j); assert_false(statp.st_dev != statn.st_dev || statp.st_ino != statn.st_ino || statp.st_mode != statn.st_mode || statp.st_nlink != statn.st_nlink || statp.st_uid != statn.st_uid || statp.st_gid != statn.st_gid || statp.st_rdev != statn.st_rdev || statp.st_size != statn.st_size || statp.st_blksize != statn.st_blksize || statp.st_blocks != statn.st_blocks || statp.st_atime != statn.st_atime || statp.st_mtime != statn.st_mtime || statp.st_ctime != statn.st_ctime); /* { printf("%s: %s\n", fname, where); encode_stat(where, &statn, sizeof(statn), 0, 0); printf("%s: %s\n", fname, where); printf("NOT EQAL\n"); } */ //printf("%d files examined\n", i); to_base64(UINT32_MAX, where); //printf("UINT32_MAX=%s\n", where); int xx = 0; int len; char buf[100]; char junk[100]; // int i; #ifdef xxxx for (i=0; i < 1000; i++) { bin_to_base64(buf, sizeof(buf), (char *)&xx, 4, true); printf("xx=%s\n", buf); xx++; } #endif junk[0] = 0xFF; for (i=1; i<100; i++) { junk[i] = junk[i-1]-1; } len = bin_to_base64(buf, sizeof(buf), junk, 16, true); //printf("len=%d junk=%s\n", len, buf); strcpy(junk, "This is a sample string"); len = bin_to_base64(buf, sizeof(buf), junk, strlen(junk), true); buf[len] = 0; base64_to_bin(junk, sizeof(junk), buf, len); //printf("buf=<%s>\n", junk); }
bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream) { BSOCK *sd = jcr->store_bsock; char attribs[MAXSTRING]; char attribsEx[MAXSTRING]; int attr_stream; int stat; #ifdef FD_NO_SEND_TEST return true; #endif Dmsg1(300, "encode_and_send_attrs fname=%s\n", ff_pkt->fname); /* Find what data stream we will use, then encode the attributes */ if ((data_stream = select_data_stream(ff_pkt)) == STREAM_NONE) { /* This should not happen */ Jmsg0(jcr, M_FATAL, 0, _("Invalid file flags, no supported data stream type.\n")); return false; } encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI, data_stream); /* Now possibly extend the attributes */ attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt); Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx); jcr->lock(); jcr->JobFiles++; /* increment number of files sent */ ff_pkt->FileIndex = jcr->JobFiles; /* return FileIndex */ pm_strcpy(jcr->last_fname, ff_pkt->fname); jcr->unlock(); /* * Send Attributes header to Storage daemon * <file-index> <stream> <info> */ if (!sd->fsend("%ld %d 0", jcr->JobFiles, attr_stream)) { Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror()); return false; } Dmsg1(300, ">stored: attrhdr %s\n", sd->msg); /* * Send file attributes to Storage daemon * File_index * File type * Filename (full path) * Encoded attributes * Link name (if type==FT_LNK or FT_LNKSAVED) * Encoded extended-attributes (for Win32) * * For a directory, link is the same as fname, but with trailing * slash. For a linked file, link is the link. */ if (ff_pkt->type != FT_DELETED) { /* already stripped */ strip_path(ff_pkt); } if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) { Dmsg2(300, "Link %s to %s\n", ff_pkt->fname, ff_pkt->link); stat = sd->fsend("%ld %d %s%c%s%c%s%c%s%c", jcr->JobFiles, ff_pkt->type, ff_pkt->fname, 0, attribs, 0, ff_pkt->link, 0, attribsEx, 0); } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE) { /* Here link is the canonical filename (i.e. with trailing slash) */ stat = sd->fsend("%ld %d %s%c%s%c%c%s%c", jcr->JobFiles, ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0, attribsEx, 0); } else { stat = sd->fsend("%ld %d %s%c%s%c%c%s%c", jcr->JobFiles, ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0); } if (ff_pkt->type != FT_DELETED) { unstrip_path(ff_pkt); } Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg); if (!stat) { Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror()); return false; } sd->signal(BNET_EOD); /* indicate end of attributes data */ return true; }