Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
RENAME_OPERATION = "rename"
COPY_OPERATION = "copy"
UPDATE_ATTRS_OPERATION = "update_attrs"
CREATEDIR_OPERATION = "createdir"
)

const (
Expand Down
71 changes: 71 additions & 0 deletions code/go/0chain.net/blobbercore/allocation/newfilechange.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,79 @@ type NewFileChange struct {
IsFinal bool `json:"is_final,omitempty"`
}

func (nf *NewFileChange) CreateDir(ctx context.Context, allocationID, dirName, allocationRoot string) (*reference.Ref, error) {
path := filepath.Clean(dirName)
tSubDirs := reference.GetSubDirsFromPath(path)

rootRef, err := reference.GetReferencePath(ctx, allocationID, nf.Path)
if err != nil {
return nil, err
}

dirRef := rootRef
treelevel := 0
for {
found := false
for _, child := range dirRef.Children {
if child.Type == reference.DIRECTORY && treelevel < len(tSubDirs) {
if child.Name == tSubDirs[treelevel] {
dirRef = child
found = true
break
}
}
}
if found {
treelevel++
continue
}
if len(tSubDirs) > treelevel {
newRef := reference.NewDirectoryRef()
newRef.AllocationID = dirRef.AllocationID
newRef.Path = "/" + strings.Join(tSubDirs[:treelevel+1], "/")
newRef.ParentPath = "/" + strings.Join(tSubDirs[:treelevel], "/")
newRef.Name = tSubDirs[treelevel]
newRef.LookupHash = reference.GetReferenceLookup(dirRef.AllocationID, newRef.Path)
dirRef.AddChild(newRef)
dirRef = newRef
treelevel++
continue
} else {
break
}
}

var newDir = reference.NewDirectoryRef()
newDir.ActualFileSize = 2
newDir.AllocationID = dirRef.AllocationID
newDir.MerkleRoot = nf.MerkleRoot
newDir.Name = dirName
newDir.Size = 2
newDir.NumBlocks = 2
newDir.ParentPath = dirRef.Path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be

newDir.ActualFileSize = 0
newDir.Size = 0
newDir.NumBlocks = 0

newDir.WriteMarker = allocationRoot
dirRef.AddChild(newDir)

if _, err := rootRef.CalculateHash(ctx, true); err != nil {
return nil, err
}

stats.NewDirCreated(ctx, dirRef.ID)
return rootRef, nil
}

func (nf *NewFileChange) ProcessChange(ctx context.Context,
change *AllocationChange, allocationRoot string) (*reference.Ref, error) {

if change.Operation == CREATEDIR_OPERATION {
err := nf.Unmarshal(change.Input)
if err != nil {
return nil, err
}

return nf.CreateDir(ctx, nf.AllocationID, nf.Path, allocationRoot)
}

path, _ := filepath.Split(nf.Path)
path = filepath.Clean(path)
tSubDirs := reference.GetSubDirsFromPath(path)
Expand Down Expand Up @@ -117,6 +187,7 @@ func (nf *NewFileChange) ProcessChange(ctx context.Context,
if _, err := rootRef.CalculateHash(ctx, true); err != nil {
return nil, err
}

stats.NewFileCreated(ctx, newFile.ID)
return rootRef, nil
}
Expand Down
8 changes: 8 additions & 0 deletions code/go/0chain.net/blobbercore/filestore/fs_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,14 @@ func (fs *FileFSStore) GetMerkleTreeForFile(allocationID string, fileData *FileI
return mt, nil
}

func (fs *FileFSStore) CreateDir(dirName string) error {
return createDirs(dirName)
}

func (fs *FileFSStore) DeleteDir(allocationID, dirPath, connectionID string) error {
return nil
}

func (fs *FileFSStore) WriteFile(allocationID string, fileData *FileInputData,
infile multipart.File, connectionID string) (*FileOutputData, error) {

Expand Down
2 changes: 2 additions & 0 deletions code/go/0chain.net/blobbercore/filestore/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ type FileObjectHandler func(contentHash string, contentSize int64)
type FileStore interface {
WriteFile(allocationID string, fileData *FileInputData, infile multipart.File, connectionID string) (*FileOutputData, error)
DeleteTempFile(allocationID string, fileData *FileInputData, connectionID string) error
CreateDir(dirName string) error
DeleteDir(allocationID, dirPath, connectionID string) error
GetFileBlock(allocationID string, fileData *FileInputData, blockNum int64, numBlocks int64) ([]byte, error)
CommitWrite(allocationID string, fileData *FileInputData, connectionID string) (bool, error)
//GetMerkleTreeForFile(allocationID string, fileData *FileInputData) (util.MerkleTreeI, error)
Expand Down
14 changes: 14 additions & 0 deletions code/go/0chain.net/blobbercore/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ func SetupHandlers(r *mux.Router) {
r.HandleFunc("/v1/file/rename/{allocation}", common.UserRateLimit(common.ToJSONResponse(WithConnection(RenameHandler))))
r.HandleFunc("/v1/file/copy/{allocation}", common.UserRateLimit(common.ToJSONResponse(WithConnection(CopyHandler))))
r.HandleFunc("/v1/file/attributes/{allocation}", common.UserRateLimit(common.ToJSONResponse(WithConnection(UpdateAttributesHandler))))
r.HandleFunc("/v1/dir/{allocation}", common.UserRateLimit(common.ToJSONResponse(WithConnection(CreateDirHandler)))).Methods("POST")
r.HandleFunc("/v1/dir/{allocation}", common.UserRateLimit(common.ToJSONResponse(WithConnection(CreateDirHandler)))).Methods("DELETE")
r.HandleFunc("/v1/dir/rename/{allocation}", common.UserRateLimit(common.ToJSONResponse(WithConnection(CreateDirHandler)))).Methods("POST")

r.HandleFunc("/v1/connection/commit/{allocation}", common.UserRateLimit(common.ToJSONResponse(WithConnection(CommitHandler))))
r.HandleFunc("/v1/file/commitmetatxn/{allocation}", common.UserRateLimit(common.ToJSONResponse(WithConnection(CommitMetaTxnHandler))))
Expand Down Expand Up @@ -259,6 +262,17 @@ func CopyHandler(ctx context.Context, r *http.Request) (interface{}, error) {
return response, nil
}

/*CreateDirHandler is the handler to respond to create dir for allocation*/
func CreateDirHandler(ctx context.Context, r *http.Request) (interface{}, error) {
ctx = setupHandlerContext(ctx, r)
response, err := storageHandler.CreateDir(ctx, r)
if err != nil {
return nil, err
}

return response, nil
}

/*UploadHandler is the handler to respond to upload requests fro clients*/
func UploadHandler(ctx context.Context, r *http.Request) (interface{}, error) {
ctx = setupHandlerContext(ctx, r)
Expand Down
82 changes: 82 additions & 0 deletions code/go/0chain.net/blobbercore/handler/object_operation_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,88 @@ func (fsh *StorageHandler) DeleteFile(ctx context.Context, r *http.Request, conn
return nil, common.NewError("invalid_file", "File does not exist at path")
}

func (fsh *StorageHandler) CreateDir(ctx context.Context, r *http.Request) (*blobberhttp.UploadResult, error) {
allocationTx := ctx.Value(constants.ALLOCATION_CONTEXT_KEY).(string)
clientID := ctx.Value(constants.CLIENT_CONTEXT_KEY).(string)

allocationObj, err := fsh.verifyAllocation(ctx, allocationTx, false)
if err != nil {
return nil, common.NewError("invalid_parameters", "Invalid allocation id passed."+err.Error())
}

valid, err := verifySignatureFromRequest(allocationTx, r.Header.Get(common.ClientSignatureHeader), allocationObj.OwnerPublicKey)
if !valid || err != nil {
return nil, common.NewError("invalid_signature", "Invalid signature")
}

allocationID := allocationObj.ID

if len(clientID) == 0 {
return nil, common.NewError("invalid_operation", "Operation needs to be performed by the owner or the payer of the allocation")
}

dirPath := r.FormValue("dir_path")
if len(dirPath) == 0 {
return nil, common.NewError("invalid_parameters", "Invalid dir path passed")
}

exisitingRef := fsh.checkIfFileAlreadyExists(ctx, allocationID, dirPath)
if allocationObj.OwnerID != clientID && allocationObj.PayerID != clientID {
return nil, common.NewError("invalid_operation", "Operation needs to be performed by the owner or the payer of the allocation")
}

if exisitingRef != nil {
return nil, common.NewError("duplicate_file", "File at path already exists")
}

connectionID := r.FormValue("connection_id")
if len(connectionID) == 0 {
return nil, common.NewError("invalid_parameters", "Invalid connection id passed")
}

connectionObj, err := allocation.GetAllocationChanges(ctx, connectionID, allocationID, clientID)
if err != nil {
return nil, common.NewError("meta_error", "Error reading metadata for connection")
}

mutex := lock.GetMutex(connectionObj.TableName(), connectionID)
mutex.Lock()
defer mutex.Unlock()

allocationChange := &allocation.AllocationChange{}
allocationChange.ConnectionID = connectionObj.ConnectionID
allocationChange.Size = 0
allocationChange.Operation = allocation.CREATEDIR_OPERATION
connectionObj.Size += allocationChange.Size
var formData allocation.NewFileChange
formData.Filename = dirPath
formData.Path = dirPath
formData.AllocationID = allocationID
formData.ConnectionID = connectionID
formData.ActualHash = "-"
formData.ActualSize = 1

connectionObj.AddChange(allocationChange, &formData)

err = filestore.GetFileStore().CreateDir(dirPath)
if err != nil {
return nil, common.NewError("upload_error", "Failed to upload the file. "+err.Error())
}

err = connectionObj.ApplyChanges(ctx, "/")
if err != nil {
return nil, err
}

result := &blobberhttp.UploadResult{}
result.Filename = dirPath
result.Hash = ""
result.MerkleRoot = ""
result.Size = 0

return result, nil
}

//WriteFile stores the file into the blobber files system from the HTTP request
func (fsh *StorageHandler) WriteFile(ctx context.Context, r *http.Request) (*blobberhttp.UploadResult, error) {

Expand Down
8 changes: 8 additions & 0 deletions code/go/0chain.net/blobbercore/stats/filestats.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ func (FileStats) TableName() string {
return "file_stats"
}

func NewDirCreated(ctx context.Context, refID int64) {
db := datastore.GetStore().GetTransaction(ctx)
stats := &FileStats{RefID: refID}
stats.NumBlockDownloads = 0
stats.NumUpdates = 1
db.Save(stats)
}

func NewFileCreated(ctx context.Context, refID int64) {
db := datastore.GetStore().GetTransaction(ctx)
stats := &FileStats{RefID: refID}
Expand Down